@astrojs/node, not a Cloudflare Worker. Easier to reason about, easier to debug locally, no edge-specific quirks.REDIS_URL into the web service. Neuromast's STORAGE_KIND=redis factory picks it up automatically.neuromast/ code. Railway watches the branch you connect, so it needs a repo you control. Fork Axol, or copy neuromast/ into a fresh repo.package.json and runs npm install + the build + start script. A Dockerfile is optional.neuromast/ to your own GitHub repoIf 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
Railway dashboard → New Project → Deploy 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.
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.
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.
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).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.
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.
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.
Same flow as any Railway project: git push. The connected branch triggers a build; the Deployments tab shows status per commit.
POLL_TOKEN: re-run lateral-line/install.sh locally with the new value to regenerate the launchd plist.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.
If you forked the whole Axol repo, make sure Root Directory in the service's Settings is neuromast. Without it Railway tries to build from the repo root (no package.json) and bails.
ADAPTER=node isn't set, so Astro built the Cloudflare bundle, which expects a Workers runtime. Add ADAPTER=node in Variables and redeploy.
The Redis plugin isn't attached to the service, or REDIS_URL isn't a reference variable. In Variables, check that REDIS_URL shows as $ (Railway's template syntax), not a hardcoded value.
401 on every request
The service deployed but POLL_TOKEN or SHARED_SECRET isn't set, or they don't match what your forwarder sends. Dashboard → Variables → confirm the values match.
Railway doesn't auto-expose domains. Settings → Networking → Generate Domain to get the *.up.railway.app URL.