Skip to contentNode.js on every plan · private Redis & PostgreSQLSee what's included →

Guides

How to run Node.js, Go, Rust or any binary on shared hosting

Run a Node server, a compiled Go or Rust binary, or a Python script as a worker process on a Litehost plan, proxied onto your domain with its own log.

Yes. A worker process is any command the panel keeps running inside your site’s container. It does not have to be PHP. Node.js is a first class option with its own version picker, and the Custom type runs whatever you ship, including compiled Go and Rust binaries. Worker processes are on every plan.

A Node.js server

Open the site, then Advanced and Worker processes, click Launch and pick Node.js.

  • Version. Any release from 0.12 to the current major. The version is installed for this site on first start, which takes a minute, and reused after that.
  • Startup command. node server.js, npm start, or whatever your app uses.
  • Working directory. The folder that holds package.json.
  • HTTP proxy. On, with the port your app listens on. Leave the path empty to put the app on the whole domain, or set a path such as api to mount it at https://yourdomain.com/api. Turn websocket upgrade on if the app uses websockets.

Your app must listen on 0.0.0.0, not localhost, so the proxy can reach it from outside the process. The proxy strips the path prefix before forwarding, so an app mounted at /api receives requests at /.

Run npm install over SSH or in a GitHub deploy build script before the first launch. The worker does not install dependencies for you.

A Go or Rust binary

There is no Go or Rust compiler in the container, so build the binary elsewhere and ship the result.

Build for the server’s platform, which is Linux on x86_64. For Go that is one command on any machine:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/server .

For Rust, build with the x86_64-unknown-linux-musl target, or let GitHub Actions do it and download the release in your build script. Static binaries are the safe choice. A dynamically linked binary has to find its libraries inside the container, and musl avoids the question.

Commit the binary, or download it in the build script, then launch a Custom worker with the command ./bin/server, the working directory that contains it, and the HTTP proxy set to the port it listens on. The log shows the binary’s own output.

Both of these were tested while writing this guide: a Go HTTP server committed to a repository and deployed from GitHub, and a Rust file server downloaded as a prebuilt release in the build script, each reachable on its own path on the test domain.

Python and everything else

Python 3.12 is installed, so python3 app.py works as a Custom worker. Install packages into a virtual environment inside the site over SSH first, then use the environment’s interpreter in the command, for example .venv/bin/python app.py.

Anything else that runs on Linux and listens on a port follows the same pattern. If it is a single file you can run from a terminal, it can be a worker.

Rules that are easy to miss

  • Fill in the working directory. A worker with an empty working directory never starts.
  • Single quotes only. The command runs inside a shell wrapper that breaks on a double quote. Put anything complicated in a script file and make the command ./run.sh.
  • The log only keeps the latest attempt. A worker that crashes at startup restarts every few seconds and clears its log each time, so the real error is never visible in the panel. Run the command once over SSH from the same directory to see it.
  • Every change restarts every worker on the site. Adding or editing a worker briefly restarts the others.
  • Deploys do not restart workers. After a GitHub deploy, press Restart container on the site overview, or have the app watch for a file change and exit so the panel restarts it.

What a worker gets

The worker runs as your site’s own user, inside its container, with the same resource limits as the site. It can reach your site’s MySQL through the socket at /run/mysqld/mysqld.sock (there is nothing listening on 127.0.0.1:3306, so set the driver’s socket path rather than a host and port) and, on every Laravel Hosting plan and on Business and up elsewhere, its Redis on 127.0.0.1:6379. It can read and write anything in your site’s home directory. It cannot see other sites on the server.

Keep reading

Other guides