Skip to content
New storyWe built Skald to count visitors. It caught an AI-key thief.
SkaldEvery visit, truly told.

Self-host · Railway

Self-hosted analytics on Railway, with no server to manage

Self-hosted analytics on Railway is one service from the Skald image and one volume for its history. Railway gives it HTTPS; your sites send it their logs.

Self-hosted analytics on Railway means running Skald's Docker image as a Railway service with a volume at /var/lib/skald. Railway keeps it up and gives it an address; Skald keeps the history on the volume and takes your sites' logs by HTTPS. One of the ways to self-host Skald free.

30-day free trial · no card · we set it up within one working day · free to self-host

Railway service · skald · sampleone replica
  1. image ghcr.io/spcaeo/skald:latestsource
  2. volume /var/lib/skaldhistory
  3. PORT 8080variable
  4. SKALD_SITE example.comvariable
  5. SKALD_INGEST truevariable
  6. domain https://stats.example.comHTTPS

Sample settings for one Railway service. Your own names go where example.com is.

[01] deploy

Deploy Skald on Railway in six steps

All in Railway's dashboard, plus two commands in the service's shell. There is no one-click template yet, so each step is a button you press yourself.

  1. 1. Deploy the image

    New project > Deploy a Docker image: ghcr.io/spcaeo/skald:latest. Or Deploy from GitHub repo with your fork: Railway builds docker/Dockerfile. Copy deploy/railway.json to the fork's root first, so Railway finds the Dockerfile path and the health check.

  2. 2. Add a volume

    Right-click the service, or use the command palette, and add a volume with the mount path /var/lib/skald. A service with a volume runs one replica and redeploys with a short stop.

  3. 3. Set the variables

    SKALD_SITE, SKALD_HOSTS, SKALD_TIMEZONE, SKALD_INGEST=true, SKALD_LOG_DIR and PORT=8080. The next fold lists each one.

  4. 4. Give it an address

    Settings > Networking > Generate Domain, or add your own domain and the CNAME record Railway shows. Put that https:// address in SKALD_BASE_URL.

  5. 5. Make the first owner

    Open the service's shell with railway ssh or from the dashboard, and run skald accounts init. It prints a link to set the password.

  6. 6. Find the proxy

    Railway does not publish its proxies' addresses. One command in the shell prints them; set SKALD_TRUSTED_PROXIES to their range and redeploy.

[02] variables

The Railway variables Skald reads

Set them in the service's Variables tab. Railway redeploys the service when they change.

Railway mounts a new volume owned by root. Skald's container starts as root only long enough to give /var/lib/skald to its own user, 10001, then drops to that user. So RAILWAY_RUN_UID=0 is not needed: it would run everything as root.

Sample values for example.com
VariableSample value and what it does
SKALD_SITEexample.com: your site's host name
SKALD_HOSTSexample.com www.example.com: the names to count
SKALD_TIMEZONEAmerica/New_York: where your day starts and ends
SKALD_INGESTtrue: take the site's log lines by HTTPS
SKALD_LOG_DIR/var/lib/skald/ingest/example.com: where those lines are kept
PORT8080: the port Railway sends traffic to
SKALD_BASE_URLhttps://stats.example.com: Skald's own address, from step 4
SKALD_TRUSTED_PROXIESempty until step 6, then the range peers shows

[03] in the shell

Two commands in the service's shell

Open the shell with railway ssh or from the service in the dashboard. Change the name and the email in the first one to your own before you copy.

Railway shell · edit the name and email first
$ skald accounts init --org "Example Co" --owner-email owner@example.com

Prints a link that sets the owner's password.

Railway shell · while the dashboard loads
$ python3 /opt/skald/docker/entrypoint.py peers

Prints the addresses connected to port 8080: Railway's proxy, not you.

Why every visitor has one address until you do this

Railway's proxy opens every connection to Skald, so without step 6 each visitor has the proxy's address: one sign-in limit for everyone, and returning visitors run together.

  1. Leave SKALD_TRUSTED_PROXIES empty. Open the dashboard, and while it loads, run peers.
  2. Set SKALD_TRUSTED_PROXIES to the smallest private range that holds what it printed: 10.0.0.0/8 for 10.x.x.x, 100.64.0.0/10 for 100.64.x.x to 100.127.x.x. Keep SKALD_REAL_IP_HEADER at its default, X-Forwarded-For. Redeploy.
  3. Check: Internal addresses > Add my current address must show your own public address. Remove the entry after.

If it shows another public address on every try, a CDN sits in front of the proxy. Empty the setting again and ask Railway's support which header holds the visitor's address. Skald refuses 0.0.0.0/0.

[04] your site's log

Send your site's visits to Skald on Railway

Railway has no log of your website, so the site's requests arrive by HTTPS. SKALD_INGEST=true and SKALD_LOG_DIR turn the receiving end on. Then pick where your site runs.

In the dashboard, Settings > Connections > Send this site's visits to Skald fills in the send address and a sending token for you, and ends with Test connection.

tap one

One command on the web server

On the site's nginx or Apache server, with or without Docker, one command finds the access log and sends its new lines to this Skald. Skald makes the sending token for you.

curl -fsSL https://<your Skald>/traffic-kit/<code> | sudo bash

A template: your Skald shows the real line. Its link works once, for 24 hours.

[05] keeping it

The volume, backups and upgrades on Railway

Everything Skald keeps is on the volume: the history, accounts, settings, its own backups and the shipped log lines of the last days.

  1. Pick the volume size

    Railway lists volume sizes per plan on its own pricing page, and the trial tier's volume is small. Check it before you choose a plan.

  2. Backups on the volume

    Skald makes a nightly and a weekly copy of its history, each restored into a scratch file and checked before it counts. Run skald backup in the shell for one now.

  3. Upgrades

    Take a backup, then change the image tag in the service's settings and redeploy. The databases are brought up to date at start. Pin :2 to get every 2.x release and never a breaking one.

What it does not do on Railway

  • It does not scale past one replica. The history is SQLite on one volume; never add a second copy.
  • It has no log of your website on Railway, so the site's log is sent to it. A site with no server or CDN log (the script tag alone) shows no AI crawlers and no bots.
  • A service without a volume loses the history at every redeploy.
  • Railway does not publish its proxies' addresses, so the trusted range is yours to find and to check again after Railway changes its network.

questions

Self-hosted analytics on Railway FAQ

Straight answers, including what Skald does not do.

Is there a one-click Deploy on Railway button for Skald?

Not yet. A Railway button needs a template published from Railway's dashboard by the project's owner. Until there is one, deploy the image by hand: it takes six short steps.

Do I need RAILWAY_RUN_UID=0 for the volume?

No. Railway mounts a new volume owned by root, so Skald's container starts as root only long enough to give /var/lib/skald to its own user, 10001, then drops to that user. RAILWAY_RUN_UID=0 would run everything as root.

Why does every visitor show the same address on Railway?

Railway puts a proxy in front of the service and does not publish its addresses. Until you tell Skald which proxy to believe, every visitor has the proxy's address. Run the peers command in the service's shell, then set SKALD_TRUSTED_PROXIES to the smallest private range that holds the addresses it prints.

How big a volume does Skald need on Railway?

Railway lists volume sizes per plan on its own volumes page, and the trial tier's volume is small. Skald keeps its history, accounts, backups and the shipped logs of the last days on the volume, so check Railway's pricing page before you choose.

How does my website's traffic reach Skald on Railway?

By HTTPS posts. A site on its own server runs one command that sends its log; a site on Vercel uses a log drain; a site behind Cloudflare uses the Skald Worker. SKALD_INGEST=true and SKALD_LOG_DIR turn the receiving end on.

$ tail -f access.log | skald

See what AI does with your site. Free for 30 days.

No card. We set up hosted Skald for you within one working day, or you self-host it free. Every line of your log, sorted and added up.

Start free trial Live demo