Full disclosure up front: I maintain a Railway template for this and get a kickback if you deploy through it. That's the whole pitch — everything below is the actual writeup.
I've been poking at the self-improving-agent space (OpenClaw and friends) and wanted to try Nous Research's Hermes Agent without handing it API keys to a hosted box. It's genuinely interesting — it accumulates skills over sessions instead of starting cold every time — but self-hosting it on a PaaS like Railway surfaces two gotchas that aren't obvious from the upstream docs, and one design decision that's easy to trip over if you're used to disabling auth "for now."
1. The dashboard fails closed, not open
Since Nous Research's June 2026 hardening pass, the Hermes dashboard refuses to bind to a non-loopback address without a registered auth provider. If you leave the password variable empty expecting an open dashboard for local testing, you don't get one — you get no dashboard at all, and HERMES_DASHBOARD_INSECURE is accepted and silently ignored. It fails safe, which I'd rather have than the alternative, but it means "just don't set a password" isn't a valid quick-start path anymore. The fix I ended up with: generate a password on first boot if none is supplied, persist it to the volume so it survives redeploys, and print it to the deploy logs.
if [ -z "${HERMES_DASHBOARD_BASIC_AUTH_PASSWORD:-}" ]; then
if [ -s "$pw_file" ]; then
HERMES_DASHBOARD_BASIC_AUTH_PASSWORD="$(cat "$pw_file")"
else
HERMES_DASHBOARD_BASIC_AUTH_PASSWORD="$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 24)"
mkdir -p "$HERMES_HOME"
printf '%s' "$HERMES_DASHBOARD_BASIC_AUTH_PASSWORD" > "$pw_file"
fi
echo "[railway] generated dashboard password: $HERMES_DASHBOARD_BASIC_AUTH_PASSWORD" >&2
fi
2. Railway injects its own PORT, and Hermes has to follow it, not its own default
Railway sets PORT=8080 on every service at runtime — it doesn't show up in the variables list, it's just there. Hermes's dashboard defaults to 9119. Point Railway's domain at 9119 (Hermes's own default) and you get a clean 502 with nothing wrong in the logs — the app is listening on a port nothing is routing to. The entrypoint has to read $PORT and set HERMES_DASHBOARD_PORT from it before the dashboard starts, not after.
3. The volume isn't optional, it's the entire value proposition
"Self-improving" means skills and session state live on disk under HERMES_HOME (/opt/data by default). No persistent volume means every redeploy wipes what the agent has learned, which defeats the point of running it at all rather than just calling an API.
None of this is a knock on Hermes itself — it's the normal gap between "runs great with docker run on your own box" and "runs on a platform that injects its own port and tears down containers on redeploy." If you'd rather do it yourself: the image is nousresearch/hermes-agent, and my wrapper (entrypoint + Dockerfile, MIT, nothing hidden) is at bon5co/hermes-agent-railway if you want to see exactly what it does or run it on your own infra instead of Railway.
If you'd rather skip wiring it up yourself, the Railway template does all three of the above automatically — one variable on the form (the dashboard password, pre-filled with a generated secret), everything else baked in: https://railway.com/deploy/hermes-agent-or-openclaw-alternative-not?referralCode=Z1xivh&utm_medium=integration&utm_source=template&utm_campaign=inventory
Worth knowing before you commit to it either way: this is a fast-moving project and the agent's behavior/skill format has already changed shape once in a few months, so don't treat whatever it learns as long-term stable state — export anything you care about.
Top comments (0)