CodePlans / Deploy

Deploy CodePlans

Step-by-step guides for Railway, Fly.io, Render and any Docker host. Expect about ten minutes from a fork to your first sign-in.

Two decisions

Every guide below works the same way: the platform builds the repo's Dockerfile, CodePlans applies its database migrations when it starts, and you create the first account in the browser using a setup code from the server log.

1 · Where the code comes from
fork
Fork SylonZero/CodePlans to your GitHub account. Platforms deploy from your fork, and to update you click Sync fork on GitHub.
branch
master is the latest release line.
2 · Which database
SQLite
The default and the simplest. Needs a 1 GB volume mounted at /data. One instance.
Postgres
For managed backups or several instances. Set DATABASE_URL and AUTH_SECRET. There's no SQLite→Postgres move yet, so pick it up front if you'll need it.

Deploy on Railway

All in the browser. The repo's railway.json tells Railway to build the Dockerfile and to check /api/health before switching traffic to a new deploy.

  1. Create a service from your fork

    At railway.com choose New Project → Deploy from GitHub repo and pick your fork. The first time, Railway asks you to install its GitHub app and choose which repositories it can see.

    Railway starts building straight away. The first deploy stops with a volume error on SQLite. That's expected: CodePlans won't run on storage that each deploy wipes. The next step fixes it.

  2. Attach storage

    On the project canvas, right-click the CodePlans service → Attach volume, and set the mount path to /data. Railway redeploys the service with the volume in place.

    Using Postgres instead? Skip the volume. Choose + Create → Database → PostgreSQL. Then on the CodePlans service open Variables and add DATABASE_URL = ${{Postgres.DATABASE_URL}}, and AUTH_SECRET = the output of openssl rand -base64 32.
  3. Give it a public address

    Open the service → Settings → Networking → Generate Domain. If Railway asks for a port, accept the one it suggests. CodePlans picks up the domain by itself, so there's no URL to configure.

  4. Copy the setup code from the logs

    Open Deployments, click the latest deployment, then Deploy Logs. Look for the [setup] line:

    [boot] migrations: applied 33, 33 total, schema up to date [setup] No accounts yet. Open https://codeplans-production.up.railway.app/setup and enter the setup code: K7QM-4XZP-W2HD
  5. Open the deployed service and claim it

    Open the domain. Any page sends you to /setup. Enter the setup code, your name, email and password, and a workspace name. You're signed in as the owner, and /setup closes for good.

Updating: click Sync fork on your fork's GitHub page. Railway redeploys automatically, and the new version applies any migrations before it takes traffic.

Deploy on Fly.io

From a terminal with flyctl installed. The repo's fly.toml sets up SQLite on a 1 GB volume, on one machine that sleeps when idle.

  1. Get the code and sign in

    git clone https://github.com/<you>/CodePlans.git && cd CodePlans
    fly auth login
  2. Create the app

    fly launch --copy-config --no-deploy

    Pick an app name and region. Decline any offer to add a database: the volume comes from fly.toml.

  3. Deploy

    fly deploy

    The first deploy creates the codeplans_data volume. If it says the volume is missing, run fly volumes create codeplans_data --size 1 --region <region> and deploy again.

    Using Postgres instead? Delete the [[mounts]] section from fly.toml. Create a database with fly mpg create and attach it with fly mpg attach <cluster> -a <app>, which sets DATABASE_URL. Also run fly secrets set AUTH_SECRET=$(openssl rand -base64 32).
  4. Copy the setup code

    fly logs # look for the [setup] line
  5. Open it and claim it

    fly open

    Enter the code at /setup to create the owner account.

Updating: git pull and fly deploy. Keep SQLite apps on one machine (fly scale count 1). Set AUTH_URL if you add a custom domain.

Deploy on Render

In the browser. Persistent disks need a paid instance type. Use Postgres if you want to stay on a free one.

  1. Create a web service from your fork

    In the Render dashboard choose New → Web Service, connect GitHub and pick your fork. Render detects the Dockerfile, so leave the language as Docker.

  2. Attach storage

    Choose a paid instance type. Under Advanced, Add Disk with mount path /data and 1 GB. Set Health Check Path to /api/health, then Deploy Web Service.

    Using Postgres instead? Skip the disk. Create New → Postgres, copy its Internal Database URL, and add it to the web service's Environment as DATABASE_URL, with AUTH_SECRET = openssl rand -base64 32.
  3. Copy the setup code

    Open the service's Logs and find the [setup] line.

  4. Open it and claim it

    Open the onrender.com address at the top of the service page and enter the code at /setup.

Updating: sync your fork. Render redeploys on every push to the branch it watches.

Any server with Docker

A VM, a home server or a NAS. The named volume keeps the database across upgrades.

  1. Build and run

    git clone https://github.com/SylonZero/CodePlans.git && cd CodePlans
    docker build -t codeplans .
    docker run -d --name codeplans -p 3000:3000 -v codeplans-data:/data --restart unless-stopped codeplans
  2. Copy the setup code

    docker logs codeplans | grep setup
  3. Open it and claim it

    Go to http://<server>:3000 and enter the code. Behind a reverse proxy or on a domain, add -e AUTH_URL=https://your.domain to docker run.

    Using Postgres instead? The deployment guide has a compose.yaml with CodePlans and Postgres together.
Updating: git pull, rebuild, then docker rm -f codeplans and run the same docker run again. The volume keeps your data.

Claim it, then invite your team

The setup page asks for the code from the log, then your name, email, password and a workspace name. Only someone who can read the server log can claim the instance. The code stays the same across restarts, so you can come back to it.

Next, invite people from the Team page. Sign-up is invite-only unless you set REGISTRATION=open. Then connect AI agents at https://<your-domain>/api/mcp with a key from Settings → API Keys. Email and Slack notifications are set up in Settings too.

Prefer no browser step? Set ADMIN_EMAIL and ADMIN_PASSWORD before the first start.

Connect AI agents →

The setup page: setup code, name, email, password and workspace name

If something's off

"…is not on a persistent volume"

The service is on SQLite without a volume, so CodePlans refuses to start rather than lose your data on the next deploy. Attach a volume at /data (the log names the exact path), or switch to Postgres.

No [setup] line in the logs

It only appears while the instance has no accounts. If someone already claimed it, sign in instead. Otherwise restart or redeploy the service and look again.

The health check keeps failing

Look further up the log. A failed migration or a missing AUTH_SECRET on Postgres stops the server on purpose and says why. The previous deploy keeps running meanwhile.

Sign-in fails on a custom domain

Set AUTH_URL to the public address, e.g. https://codeplans.yourteam.com. Platform domains are detected automatically.

Someone can't sign up

That's the invite-only default. Invite them from the Team page, or set REGISTRATION=open to let anyone who can reach the server join.

Every setting

The self-host page and the deployment guide list every environment variable, backups and health checks.