Self-host · Render
Self-hosted analytics on Render, from one Blueprint
Self-hosted analytics on Render is one web service from the Skald image and one persistent disk. The repository's Blueprint sets up both and asks only for your site's names.
Self-hosted analytics on Render means running Skald's Docker image as a Render web service with a persistent disk at /var/lib/skald. Render gives it HTTPS and keeps it up; Skald keeps the history on the disk 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
- web skaldservice
- image ghcr.io/spcaeo/skald:latestsource
- disk /var/lib/skald · 5 GBhistory
- health /traffic-auth/logincheck
- SKALD_SITE example.comyou fill in
- SKALD_BASE_URL https://stats.example.comHTTPS
Sample values. The Blueprint asks for your own when you deploy.
[01] deploy
Deploy Skald on Render in five steps
The repository's render.yaml is a Render Blueprint. It makes the service, the disk and the settings; you add a domain and two commands in the Shell tab.
1. Start the Blueprint
Press Deploy to Render below, or New > Blueprint and pick your fork: Render reads
render.yamlat its root.deploy/render.yamlis the same file.2. Fill in four settings
SKALD_SITE,SKALD_HOSTS,SKALD_BASE_URLandSKALD_LOG_DIR. Pick a paid instance type: a disk needs one.3. Add your domain
The service gets an
onrender.comaddress. For your own, Settings > Custom Domains, then the CNAME record Render shows. Render issues the certificate.4. Make the first owner
The service's Shell tab, then
skald accounts init. It prints a link to set the password.5. Find the proxy
Render does not publish its proxies' addresses. One command in the Shell tab prints them; set
SKALD_TRUSTED_PROXIESto their range.
[02] the Blueprint
What the Render Blueprint sets up
One web service, one disk, the settings. Nothing else: no database service, no worker, no cron job. Skald runs its own schedule inside the one service.
Render's docs do not say who owns a new disk. Either way the container hands /var/lib/skald to its own user, 10001, at the first start, then drops to that user.
| Part | What it is |
|---|---|
| Service | a web service named skald from ghcr.io/spcaeo/skald:latest |
| Port | PORT=8080 |
| Health check | /traffic-auth/login |
| Disk | skald-data, 5 GB at /var/lib/skald. It can grow later, never shrink |
| Set for you | SKALD_INGEST=true, SKALD_TIMEZONE=UTC (change it to yours) |
| Asks you | SKALD_SITE, SKALD_HOSTS, SKALD_BASE_URL, SKALD_LOG_DIR (/var/lib/skald/ingest/example.com) |
| Later | SKALD_TRUSTED_PROXIES, from step 5 |
[03] in the Shell tab
Two commands in Render's Shell tab
Open the service, then Shell. Change the name and the email in the first one to your own before you copy.
$ skald accounts init --org "Example Co" --owner-email owner@example.com
Prints a link that sets the owner's password.
$ python3 /opt/skald/docker/entrypoint.py peers
Prints the addresses connected to port 8080: Render's proxy, not you.
Set the trusted proxy
Render's proxy opens every connection to Skald and appends the visitor's address to X-Forwarded-For. Until Skald knows which proxy to believe, every visitor has the proxy's address.
- Leave
SKALD_TRUSTED_PROXIESempty. Open the dashboard, and while it loads, runpeers. - Set
SKALD_TRUSTED_PROXIESto the smallest private range that holds what it printed, for example10.0.0.0/8for 10.x.x.x. KeepSKALD_REAL_IP_HEADERat its default,X-Forwarded-For. Redeploy. - 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 Render's proxy. Empty the setting again and ask Render'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 Render
Render 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.
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.
The Skald Worker, on any Cloudflare plan
A small Worker passes every request on unchanged and, after the page has gone out, posts one record of it to this Skald. Cached pages are counted too.
A Vercel log drain
Vercel posts every request to this Skald. Log drains need Vercel Pro or Enterprise; on Hobby, only the script tag is left.
The script tag alone
One line in every page's head counts people, their clicks and their forms. It never sees AI crawlers or bots: they do not run scripts.
[05] keeping it
The disk, deploys and upgrades on Render
The disk holds everything Skald keeps: the history, accounts, settings, its own backups and the shipped log lines of the last days.
Grow the disk
Start at 5 GB.
skald doctorin the Shell tab shows how full it is. A Render disk grows, never shrinks, so grow it in small steps.A short stop per deploy
With a disk, Render stops the old instance before it starts the new one: a few seconds of downtime. Fine for Skald, which runs as one copy.
Upgrades
Run
skald backupin the Shell tab, then deploy the new image. The databases are brought up to date at start. Pin:2in the image address to get every 2.x release and never a breaking one.
What it does not do on Render
- It does not run on a free instance type: there is no disk, so every restart loses the history.
- It does not scale past one instance. The history is SQLite on one disk.
- It has no log of your website on Render, 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.
- Render does not publish its proxies' addresses, so the trusted range is yours to find and to check again after Render changes its network.
keep reading
More on self-hosted analytics on Render
questions
Self-hosted analytics on Render FAQ
Straight answers, including what Skald does not do.
Can Skald run on Render's free instance type?
Not well. A Render disk needs a paid instance type. A free instance has no disk, so Skald would lose its history at every restart. Check Render's pricing page before you choose.
What does the Skald Blueprint make on Render?
A web service from the image ghcr.io/spcaeo/skald:latest on port 8080 with the health check /traffic-auth/login, a 5 GB disk at /var/lib/skald, and the settings. It asks you for SKALD_SITE, SKALD_HOSTS, SKALD_BASE_URL and SKALD_LOG_DIR.
Can I make the Render disk bigger later?
Yes. A Render disk can grow later, but it cannot shrink. Start at 5 GB and grow it when Skald's doctor shows the disk filling.
Is there downtime when Render deploys Skald?
A few seconds. With a disk, Render stops the old instance before it starts the new one, and the service cannot scale past one instance. Both are fine for Skald, which is built to run as exactly one copy.
Why does every visitor show the same address on Render?
Render puts a proxy in front of the service and does not publish its addresses. Run the peers command in the Shell tab while the dashboard loads, then set SKALD_TRUSTED_PROXIES to the smallest private range that holds the addresses it prints, and redeploy.
$ 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.