Tephra on Railway
Three commands. HTTPS and a web address come included.
- 1
Install the Railway CLI and sign in
npm i -g @railway/cli && railway login - 2
Grab Tephra and make a project
git clone https://github.com/championswimmer/tephra && cd tephra && railway init - 3
Launch it
This sets up the server, its disk and its secrets in one go.
npm run deploy:railway - 4
Copy your setup token
You'll paste it once, when you create your login. Your server's web address is on the service page in Railway.
railway variable list --service tephra --kv | grep BOOTSTRAP
Environment variables
The steps above already set everything Tephra needs. This is the complete list for a manual install, a different host, or a change later on.
Service → Variables in Railway, or railway variable set NAME=value --service tephra.
railway variable list --service tephra --kv | grep TEPHRA_ The deploy command fills in every value below. TEPHRA_PUBLIC_URL tracks the Railway domain; set it yourself once you attach a custom domain. Do not set PORT — Railway injects it.
| Variable | When | Default | What it does |
|---|---|---|---|
TEPHRA_PUBLIC_URL | Always | none | Browser-visible origin, including the scheme (https://notes.yourname.com). Used for redirects, cookies and MCP OAuth discovery. It must match the address people open. |
TEPHRA_SESSION_SECRET | Always | none | Signs and protects browser sessions. Use at least 32 random bytes, for example openssl rand -hex 32. Never reuse the bootstrap token here. |
TEPHRA_BOOTSTRAP_TOKEN | First boot | none | One-time proof for creating the first admin account at /setup. Delete it from the environment after that account exists. |
HOST | Optional | 0.0.0.0 in the image | HTTP bind address. Leave it at 0.0.0.0 inside a container. |
PORT | Optional | 8080 | Single port for the API and the web app. Railway injects its own value, so do not set it there. |
NODE_ENV | Optional | production in the image | When set to production, session cookies are marked Secure. The container image already sets it. |
TEPHRA_DATABASE_DRIVER | Optional | sqlite | Must be sqlite. Tephra refuses to start with any other value: live storage is disk-only. |
TEPHRA_SQLITE_PATH | Optional | /data/tephra.db in the image | SQLite database file. Keep it on the persistent disk, never in the container layer. |
TEPHRA_BLOB_DRIVER | Optional | filesystem | Must be filesystem, matching the disk-only profile. |
TEPHRA_BLOB_PATH | Optional | /data/blobs in the image | Content-addressed attachment store. Must sit next to the database on the same disk. |
TEPHRA_MAX_BLOB_BYTES | Optional | 104857600 (100 MiB) | Largest attachment Tephra accepts. Platform request limits can be lower; raise both or neither. |
TEPHRA_WEB_ROOT | Optional | /app/tephra-server/apps/web/dist in the image | Directory of the built web app served by the API process. Only change it for custom builds. |
Delete TEPHRA_BOOTSTRAP_TOKEN after your first login. It only exists to create the first admin. Run railway variable delete TEPHRA_BOOTSTRAP_TOKEN --service tephra.
Want every detail, every knob? The full Railway guide is on GitHub.