docs/user/builds/railpack-and-dockerfiles.md


title: Railpack and Dockerfiles description: Build your app without a Dockerfile, or with yours, and set commands, build-time variables and CPU types.

Ployz builds your app with Railpack, so you don't need a Dockerfile. Railpack reads your repository, works out the language and framework, and builds an image that installs, builds and starts your app. If you'd rather use your own Dockerfile, you can.

Build without a Dockerfile

Every service you add from GitHub starts on Railpack, even when the repository has a Dockerfile. Railpack detects Node, Python, Ruby, PHP, Go, Rust, Java, Elixir and more; its docs list the files it looks for. Build settings are under the service's Settings → Build, and changes to them are staged until you deploy, except Preferred Builder, which applies at once.

Settings → Build: Build method, Build command and Preferred Builder

Change the build and start commands

When Railpack picks the wrong build step:

  1. Open the service and go to Settings → Build.
  2. Click Build command and enter the command, like pnpm run build.
  3. Deploy.

Railpack still works out the rest, like installing dependencies. To change how your app starts, set Start command under Settings → Deploy, like node server.js. It runs in a shell, so $PORT and && work.

For anything else, like extra system packages, add a railpack.json to the root directory or set Railpack's own RAILPACK_* variables on the service.

Build with a Dockerfile

Use your Dockerfile when you already have one that works, or when your app needs more than Railpack can work out.

The build starts in the service's root directory: COPY . . copies that folder, and Dockerfile path is relative to it. To build one app of a monorepo, set its root directory first; see Deploy a monorepo.

  1. Open the service and go to Settings → Build.
  2. Set Build method to Dockerfile.
  3. If your Dockerfile isn't Dockerfile in the root directory, enter its path in Dockerfile path.
  4. Deploy.

Dockerfile path suggests paths from the top of the repository, so with a root directory set, shorten them to start from it.

A Start command on a Dockerfile build replaces the Dockerfile's ENTRYPOINT and CMD and runs without a shell, as on an image service. See Override the start command.

Use variables at build time

Every variable of the service reaches its build, secrets included, with references to other services filled in. Changing one rebuilds the service.

  • Railpack gives them to every build step and keeps their values out of the image's metadata.

  • A Dockerfile gets them as build arguments. Declare each one a step needs with ARG:

    dockerfile
    1ARG NEXT_PUBLIC_API_URL
    2RUN npm run build

Warning

A build can keep what it reads. Docker saves the build arguments a RUN step uses in the image's history, and any step can print a value into the build log or write it into the image. Don't pass long-lived secrets to a Dockerfile as ARGs.

Builds on GitHub Actions get your variables too.

Install private packages

Builds have no SSH keys or registry logins of their own. Give the build a token through a secret variable instead. For a private npm package, add a variable NPM_TOKEN and an .npmrc next to your package.json:

ini
1//registry.npmjs.org/:_authToken=${NPM_TOKEN}

Railpack builds see NPM_TOKEN as it is. A Dockerfile needs ARG NPM_TOKEN before the install step, so give it a short-lived token. Private Git dependencies work the same way, over HTTPS with a token in the URL.

A token can't get a Dockerfile FROM a private image: use a public base image.

What a build can reach

Build steps reach the internet over IPv4, so package registries and Git hosts work. They can't reach the server running the build, the private network Ployz runs between your servers, or your services on it. Fetch what a build needs from the internet, and talk to your services after deploy.

A build step can still reach any port your services publish on a public address, like a web address on 80 and 443, and your other servers' public addresses. Don't leave anything on those addresses open without a login. It can't reach the build server's local network, like a cloud VPC or office LAN, any other private address, or the cloud's metadata service, even through a port published there. Its DNS keeps working, so port 53 stays open to any address, private ones too.

A Dockerfile ADD of a URL or Git repository reaches the internet, and nothing on the server running the build or your servers' private network, except the image servers Ployz uses to share build images between your servers. Unlike a build step, it still reaches the build server's local network. If Ployz can't put that limit in place, the build fails instead of running without it.

When your servers mix x86 and ARM

  • With Railpack, there's nothing to do: Ployz builds the service for both.
  • With a Dockerfile, the image only runs on the kind of CPU of the server that built it. A deploy that would start it on the other kind fails before it changes anything.

To deploy a Dockerfile service, switch it to Railpack, or run it on one kind of server:

  1. Turn off services on the servers of the other kind: on each one's page, under Services, turn off Run services here. This applies to every service on that server, and your next deploy moves this one off it.

  2. Build on the kind that's left: make a server of that kind the service's Preferred Builder, or build on GitHub Actions.

Good to know

  • Keep files out of the build with a .dockerignore in the root directory. It works with Railpack and with Dockerfiles.
  • Keep secrets on your computer by listing them in .gitignore. A .dockerignore keeps a file out of your image, but ployz up still uploads it. In a Git checkout, ployz up leaves out every file Git ignores, so add .env to .gitignore. If you committed .env before, Git still keeps it, so also run git rm --cached .env. Outside a Git checkout it uploads every file, so move .env out of the directory first. See Deploy a directory.