# How to deploy Gotenberg on Railway

Deploy Gotenberg on Railway with password protection and private networking, call it from your app, and keep the bill low with idle shutdown.

These are the exact steps we used to run Gotenberg on Railway for html-pdf.com.

**Quick answer.** Deploy a small Dockerfile based on `gotenberg/gotenberg:8` with `railway up`, set a basic auth username and password, and call it from your other services at `http://gotenberg.railway.internal:3000`. If you would rather not run a server, one `POST https://html-pdf.com/v1/pdf` request does the same job (see the end of this page).

## 1. Create the service from a Dockerfile

This step gives you a pinned, hardened Gotenberg service. A tiny Dockerfile lets you pin the version and pass hardening flags. Railway sets a `PORT` variable, so the first flag tells Gotenberg to use it.

```dockerfile
FROM gotenberg/gotenberg:8
CMD ["gotenberg", \
  "--api-port-from-env=PORT", \
  "--api-enable-basic-auth", \
  "--api-timeout=30s", \
  "--api-disable-download-from", \
  "--chromium-deny-private-ips", \
  "--chromium-idle-shutdown-timeout=15m", \
  "--libreoffice-disable-routes", \
  "--webhook-disable"]
```

Put it in its own folder (for example `gotenberg/Dockerfile`) and deploy with the Railway CLI.

```bash
railway up gotenberg --path-as-root --service gotenberg
```

You can also create the service from the `gotenberg/gotenberg:8` image in the dashboard and set the start command there.

## 2. Set the variables

These variables turn on password protection. Set them on the Gotenberg service.

| variable | value |
|---|---|
| `PORT` | `3000` |
| `GOTENBERG_API_BASIC_AUTH_USERNAME` | any username |
| `GOTENBERG_API_BASIC_AUTH_PASSWORD` | a long random string |

Use the CLI's stdin mode so secrets don't end up in your shell history.

```bash
openssl rand -hex 24 | railway variable set GOTENBERG_API_BASIC_AUTH_PASSWORD --stdin --service gotenberg
```

## 3. Call it over the private network

This step connects your app to Gotenberg without exposing it to the internet. Services in the same Railway project reach each other at `<service>.railway.internal`, so your app can use this URL.

```
GOTENBERG_URL=http://user:password@gotenberg.railway.internal:3000
```

```bash
curl -u user:password -F files=@index.html \
  http://gotenberg.railway.internal:3000/forms/chromium/convert/html -o out.pdf
```

Only add a public domain (Settings → Networking) if something outside Railway must call it. Keep basic auth on when you do.

## 4. Keep the cost down

One flag cuts most of the bill for low-traffic projects. Railway bills RAM by the minute, and an idle Chromium still holds memory.

`--chromium-idle-shutdown-timeout=15m` shuts Chromium down after 15 idle minutes. It restarts on the next request, which is about a second slower.

## 5. Verify

These two commands confirm the service is up and that auth is enforced. The second one should return 401.

```bash
curl -u user:password https://<your-domain>/health
curl -s -o /dev/null -w '%{http_code}\n' -F files=@index.html https://<your-domain>/forms/chromium/convert/html   # 401 without auth
```

## Or skip the server

If you just need PDFs, you can use an API instead of running Gotenberg. Running it yourself means pinning versions, rotating secrets, watching memory and patching Chromium. [html-pdf.com](https://html-pdf.com) is that same hardened Gotenberg setup as an API.

```bash
curl https://html-pdf.com/v1/pdf -H "Authorization: Bearer $HTML_PDF_KEY" \
  -d '{"html": "<h1>Invoice #042</h1>"}' -o invoice.pdf
```

There is no idle RAM bill. You get 100 free pages, then pay from $0.005 per page, and credits never expire. It also gives AI agents a remote MCP server.

## FAQ

### How much RAM does Gotenberg need on Railway?

Chromium holds memory even when idle, and Railway bills RAM by the minute. Setting `--chromium-idle-shutdown-timeout=15m` frees that memory after 15 idle minutes, at the cost of about a second on the next request.

### How do I password-protect Gotenberg on Railway?

Start Gotenberg with `--api-enable-basic-auth` and set `GOTENBERG_API_BASIC_AUTH_USERNAME` and `GOTENBERG_API_BASIC_AUTH_PASSWORD` on the service. Requests without those credentials get a 401.

### Do I need a public domain for Gotenberg on Railway?

No. Services in the same Railway project can call it at `http://gotenberg.railway.internal:3000`. Only add a public domain if something outside Railway must reach it, and keep basic auth on.

### Is there a hosted alternative to running Gotenberg?

Yes. html-pdf.com runs the same hardened setup as an API at `POST https://html-pdf.com/v1/pdf`. You get 100 free credits once with no card, and purchased credits never expire.

[Get a free API key](https://html-pdf.com/login) · [Self-host Gotenberg with Docker](https://html-pdf.com/self-host-gotenberg-docker) · [Gotenberg in n8n](https://html-pdf.com/gotenberg-n8n)
