deploy guide

Deploy to Railway

Railway docs

why pick Railway

If you're choosing between this and Webflow Cloud: Webflow Cloud is the shortest path if your alerts live near an existing Webflow site. Railway is a better fit if you're treating neuromast as just another backend service alongside your other infra, or if you want to swap the storage later (Postgres, Redis clusters, your own boxes).

prerequisites

1 · push neuromast/ to your own GitHub repo

If you forked Axol, skip to step 2. Otherwise seed a fresh repo with just the neuromast/ tree:

cp -r neuromast /tmp/my-neuromast
cd /tmp/my-neuromast
git init -b main
git add .
git commit -m "seed neuromast"
gh repo create my-neuromast --private --source=. --push

2 · create the Railway project

  1. New project from your repo

    Railway dashboard → New ProjectDeploy from GitHub repo → pick your neuromast repo. If you forked the whole Axol monorepo, set Root Directory to neuromast in the service's Settings tab so Railway builds from there instead of the repo root.

    Railway detects package.json, installs deps, and runs npm run build followed by npm start. Our start script is node ./dist/server/entry.mjs — the Astro Node adapter's standalone output.

  2. Add the Redis plugin

    In the project canvas: + New → Database → Add Redis. Railway provisions a small Redis instance in the same region and wires it up automatically.

    Open the web service's Variables tab — Railway injects REDIS_URL via a reference variable (something like $). Neuromast's storage factory auto-detects this and selects the Redis backend. Nothing else to configure.

  3. Tell Astro to build for Node

    In the web service's Variables tab, add:

    ADAPTER=node

    astro.config.mjs reads this at build time and swaps in @astrojs/node instead of the Cloudflare adapter. Output becomes a standalone Node server at dist/server/entry.mjs.

  4. Set the bearer + HMAC secrets

    Still in Variables, add the neuromast-specific secrets (mark each as a secret — Railway masks them in the UI):

    • POLL_TOKEN — bearer the local forwarder uses for /pull + /ack. openssl rand -hex 32.
    • SHARED_SECRET (optional) — query-key fallback for senders that can't sign. Same command.
    • HOOK_SCHEME_<SOURCE> + HOOK_SECRET_<SOURCE> per signed source (e.g. HOOK_SCHEME_GITHUB=github).
  5. Expose a public URL

    Service → Settings → Networking → Generate Domain. Railway gives you a <service>.up.railway.app URL. Copy it — that's your AXOL_CLOUD_URL.

    Unlike Webflow Cloud, Railway owns the full domain; there's no mount path to worry about. Routes live at https://<your>.up.railway.app/app/api/… because neuromast's astro.config.mjs still has base: '/app' for URL parity with the Webflow deploy. Remove it if you want the routes at the root.

  6. Probe the endpoints

    export AXOL_CLOUD_URL=https://<your>.up.railway.app
    export POLL_TOKEN='the-bearer-you-set'
    export SHARED_SECRET='the-shared-key-you-set'
    
    curl -X POST "$AXOL_CLOUD_URL/app/api/hooks/smoke?key=$SHARED_SECRET" \
      -H 'content-type: application/json' \
      -d '{"title":"hello","body":"from railway"}'
    
    curl -H "Authorization: Bearer $POLL_TOKEN" "$AXOL_CLOUD_URL/app/api/pull"

    Expect 204 on the POST and a JSON body with your item on the GET. 401 on either means the bearer or shared secret mismatch. 500 or "cannot connect to Redis" in the deploy logs means REDIS_URL isn't wired — re-check the Variables tab references the Redis plugin.

3 · connect the local forwarder

Same as the Webflow deploy — point the forwarder's AXOL_CLOUD_URL at your Railway domain:

AXOL_CLOUD_URL="$AXOL_CLOUD_URL" \
AXOL_POLL_TOKEN="$POLL_TOKEN" \
./lateral-line/install.sh

With Axol running, post a test webhook and watch ~/Library/Logs/Axol/lateral-line.log for the pull → forward → ack cycle.

day-2 operations

Redeploying

Same flow as any Railway project: git push. The connected branch triggers a build; the Deployments tab shows status per commit.

Rotating secrets

  1. Railway service → Variables → edit the secret → Save. Railway restarts the service automatically.
  2. For POLL_TOKEN: re-run lateral-line/install.sh locally with the new value to regenerate the launchd plist.
  3. For HMAC secrets: update the sender's webhook config to match.

Cost

Railway's hobby plan bills by usage — a Node service + small Redis sitting idle with occasional webhook traffic runs a few dollars a month at most. Check the Usage page for a live estimate. If you'd rather cap spending hard, set a monthly credit limit in account settings.

troubleshooting