
Deploy Operately
Deploy Operately, open-source goal and project tracking
Just deployed
/var/lib/postgresql/data
Operately
Just deployed
/media
Operately for railway.app
Deploy Operately on Railway with one click.
Deploy and Host Operately on Railway
Operately is an open-source goal, project, and OKR tracking tool that replaces status-update
meetings with structured check-ins. This template runs the official operately/operately
Docker image on Railway, backed by a separate Postgres service for data storage.
About Hosting Operately
Hosting Operately on Railway means running its Elixir/Phoenix release container next to a managed Postgres instance, with Railway generating the domain, terminating TLS, and running the database migration automatically before every deploy — no server to patch, no reverse proxy to configure by hand.
Why Deploy Operately on Railway
- No server provisioning — Railway builds and runs the container from the pinned upstream image
- Postgres attaches as a managed service instead of a self-hosted database to babysit
- TLS and the domain are handled at Railway's edge, so
OPERATELY_HOSTonly needs a hostname - Migrations run automatically on every deploy via
preDeployCommand, no manual SSH step - Renovate keeps the pinned image tag current without floating on
latest
Common Use Cases
- Replacing weekly status-update meetings with asynchronous written check-ins
- Tracking OKRs and project goals with automatic progress roll-ups across a company
- Giving leadership a single, always-current view of who owns what and how it is progressing
Dependencies for Operately
- Image:
operately/operately:1.8.0(official upstream image, pinned tag) - Database: PostgreSQL, provisioned as a separate Railway service and wired in via the
DATABASE_URLreference variable — there is no SQLite fallback - Volume: a Railway volume mounted at
/mediafor uploaded files - License note: Operately's core is Apache-2.0; a separate proprietary license covers its
ee/(Enterprise Edition) subtree. This template only references the published Docker image, it does not build or redistribute the source.
🚀 Quick Start
- Click "Deploy on Railway"
- Add a Postgres service to the project and reference it as
DATABASE_URL(see below) - Set the remaining environment variables listed below
- Attach a volume at
/mediabefore sending production traffic - Wait for the build —
preDeployCommandcreates the database and runs migrations automatically — then open the generated URL
⚙️ Configuration
Environment variables
DATABASE_URL=${{Postgres.DATABASE_URL}} # reference to a separate Postgres service
SECRET_KEY_BASE=generate-a-secret # Railway "generate" button; signs/encrypts cookies
OPERATELY_BLOB_TOKEN_SECRET_KEY=generate-a-secret # signs file/blob URLs
SYSTEM_SETTINGS_ENCRYPTION_KEYS=generate-a-secret # encrypts stored settings
OPERATELY_HOST=${{RAILWAY_PUBLIC_DOMAIN}} # bare hostname, no scheme or port
OPERATELY_URL_SCHEME=https
ALLOW_LOGIN_WITH_EMAIL=yes # without this + no Google OAuth, nobody can log in
ALLOW_SIGNUP_WITH_EMAIL=yes
CERT_DOMAIN="" # must be set (empty string, not unset) — see below
CERT_EMAILS=""
CERT_DB_DIR=/opt/operately/certs
Set real values as Railway variables, never in a file in this repo. PORT defaults to 4000
and Railway sets it for you. requiredMountPath = "/media" in railway.toml — attach a volume
there before production traffic, or uploads are lost on every redeploy.
🐳 Local Development
git clone https://github.com/vergissberlin/railwayapp-operately.git
cd railwayapp-operately
cp .env.example .env
docker compose up -d
docker compose exec operately /opt/operately/bin/create_db
docker compose exec operately /opt/operately/bin/migrate
preDeployCommand only runs on Railway, so run the two commands above by hand locally. Then
open http://localhost:4000.
🤝 Contributing
Found a bug? Open an issue or a pull request. See CONTRIBUTING.md.
📝 License
MIT — see LICENSE.
Railway runtime defaults
- Healthcheck
/health· RestartON_FAILURE(10 retries) · Dockerfile build · TLS at Railway's edge, credentials only ever set as variables, never committed preDeployCommandrunspredeploy.sh(create_dbthenmigrate) — Railway only accepts one command, so chaining needed a real script, not a&&-joined string- Operately reads
$PORTdirectly, no start command or entrypoint wrapper needed CERT_DOMAIN/CERT_EMAILS/CERT_DB_DIRare set even though no real TLS cert is used here: Operately's cert-management child validates and chmods these at every boot regardless ofCERT_AUTO_RENEW, and unset values crash the app. Empty strings for the first two match the official installer's own "skip TLS" path;CERT_DB_DIR=/opt/operately/certsis anobody-owned folder baked into the image, kept outside/media(a volume's contents replace whatever the Dockerfile put at its mount path, so it isn't there by boot time).
📚 Resources
Template Content
PGDATA
PGPORT
POSTGRES_DB
POSTGRES_USER
SSL_CERT_DAYS
RAILWAY_DEPLOYMENT_DRAINING_SECONDS
Operately
vergissberlin/railwayapp-operatelyCERT_DB_DIR
CERT_DOMAIN
CERT_EMAILS
SECRET_KEY_BASE
OPERATELY_URL_SCHEME
ALLOW_LOGIN_WITH_EMAIL
ALLOW_SIGNUP_WITH_EMAIL
OPERATELY_INSTALLATION_ID
OPERATELY_BLOB_TOKEN_SECRET_KEY
SYSTEM_SETTINGS_ENCRYPTION_KEYS
