Configuration
SolidPing is configured primarily through environment variables. All environment variables use the SP_ prefix. Configuration uses hierarchical precedence: Environment variables > config.local.yml > config.yml > defaults.
Configuration Methods
- Environment Variables - Recommended for Docker and production
- Configuration File -
config.ymlin the working directory (withconfig.local.ymlfor local overrides) - Command Line - Some options can be passed via CLI flags
Quick Reference
Essential Variables
| Variable | Default | Description |
|---|---|---|
SP_DB_TYPE | sqlite | Database type: postgres, sqlite, sqlite-memory, postgres-embedded |
SP_DB_URL | - | PostgreSQL connection string |
SP_DB_DIR | . | SQLite database directory |
SP_DB_RESET | false | Reset database on startup |
SP_SERVER_LISTEN | :4000 | Server address and port |
SP_BASE_URL | http://localhost:4000 | Public URL where SolidPing is accessible |
URL layout
Everything SolidPing serves lives under a handful of fixed top-level paths:
| Path | What it serves |
|---|---|
/d | the operator dashboard |
/s | public status pages |
/docs | this documentation site |
/openapi, /openapi.yaml | the interactive API explorer and its schema |
/api | the REST API |
/metrics, /health | Prometheus scrape endpoint and health probe |
/ redirects to /d/.
The dashboard and the status pages used to be served at /dash0 and
/status0. Both prefixes answer a permanent redirect (301) onto /d and
/s, preserving the rest of the path and the query string, and they will keep
doing so — there is no sunset date. Bookmarks, links in old notification
emails, and anything you pasted into a chat before the change all still land in
the right place.
Server Configuration
| Variable | Default | Description |
|---|---|---|
SP_SERVER_LISTEN | :4000 | Listen address (e.g., :4000, 0.0.0.0:8080) |
SP_SERVER_JOB_WORKER_NB | 2 | Number of job runner goroutines |
SP_SERVER_CHECK_WORKER_NB | 3 | Number of check runner goroutines |
SP_SERVER_COMPRESSION | true | Gzip-compress JSON, HTML, CSS, JS, SVG and XML/Atom/YAML responses above 1 KiB. SolidPing compresses its own responses, so no reverse-proxy-side compression is needed — enabling one anyway is harmless, since a response that already carries Content-Encoding passes through untouched |
SP_SHUTDOWN_TIMEOUT | 30s | Graceful shutdown timeout |
SP_EXIT_WITH_PARENT | false | Shut down when the process that started SolidPing disappears, instead of being reparented to PID 1. For servers spawned by a test harness or a wrapper script; leave off under a normal supervisor |
PORT | - | Alternative to SP_SERVER_LISTEN (for PaaS compatibility) |
Custom Domains & TLS
| Variable | Default | Description |
|---|---|---|
SP_CUSTOM_DOMAIN_CNAME_TARGET | host of base_url | Hostname customers point their status-page CNAME at |
SP_CUSTOM_DOMAIN_CNAME_MODE | shared | shared (plain target) or token (per-page <token>.cname.<target>) |
SP_ACME_ENABLED | false | Terminate TLS in-server with Let's Encrypt certificates obtained on demand |
SP_ACME_EMAIL | - | ACME account contact — required when SP_ACME_ENABLED=true |
SP_ACME_CA_URL | Let's Encrypt prod | ACME directory URL (point at LE staging while testing) |
SP_ACME_LISTEN_HTTP | :80 | HTTP-01 challenge listener; redirects everything else to HTTPS |
SP_ACME_LISTEN_HTTPS | :443 | TLS listener, feeding the normal routing |
SP_ACME_FALLBACK_UPSTREAM_HTTPS | - | host:port of a second instance to hand unknown-SNI TLS connections to |
SP_ACME_FALLBACK_UPSTREAM_HTTP | - | Same next hop for plaintext :80 (HTTP-01 for the downstream's domains) |
SP_ACME_FALLBACK_UPSTREAM_PROXY_PROTOCOL | true | Send a PROXY v2 header with the original client to that next hop |
SP_ACME_PROXY_PROTOCOL | false | Read a PROXY protocol (v1/v2) preamble on both ACME listeners — needed behind a TLS passthrough, which has no X-Forwarded-For |
SP_ACME_PROXY_PROTOCOL_TRUSTED_CIDRS | - | Comma-separated CIDRs/IPs whose PROXY header is honored; headers from anywhere else are ignored. Required when SP_ACME_PROXY_PROTOCOL=true (empty fails startup) |
Enabling SP_ACME_ENABLED makes the process bind two extra ports and removes
the need for a TLS-terminating reverse proxy. Leave it off to keep TLS at your
own edge. See Custom Domains for the full setup.
SolidPing also compresses its own responses (SP_SERVER_COMPRESSION, default
true), so no reverse proxy in front of it needs to do so — enabling
proxy-side compression anyway is harmless, since a response that already
carries Content-Encoding passes through untouched.
Distributed Workers
| Variable | Default | Description |
|---|---|---|
SP_NODE_ROLE | all | Node role: all, api, jobs, checks — or a comma-separated combination (api,jobs) |
SP_NODE_REGION | - | Worker region (required when the role includes checks) |
SP_NODE_NAME | hostname | Worker identity (workers.slug and workers.name) — overrides the OS hostname |
SP_REGIONS | - | Region display definitions, as a JSON list of {slug, emoji, name} |
Use SP_NODE_ROLE to run SolidPing in a distributed configuration:
all- Single node running everything (default)api- Only serve the API and dashboardjobs- Only run background jobs (scheduling, cleanup)checks- Only execute health checks (worker mode)
api, jobs and checks can also be combined in one value, as a
comma-separated list:
SP_NODE_ROLE=api,jobs
That node serves the API/dashboard and processes background jobs, but runs no
check executor — the checks are left to separate SP_NODE_ROLE=checks nodes.
This is what you want when the check workers need a network setup the
public-facing node should not have: on a single-stack (IPv4-only) Kubernetes
cluster, check workers need hostNetwork: true to reach IPv6-only targets, and
putting the pod that serves your dashboard on the host network namespace is a
much more sensitive change than doing it for a checks-only worker. Run the main
pod as api,jobs and add a checks-only hostNetwork Deployment per region.
Rules:
allandagentare whole-node modes and cannot be combined with anything —allalready means api + jobs + checks.- A role listed twice, an unknown role, or an empty entry (
api,) aborts startup with a message naming the offending value. A typo never silently disables a subsystem. SP_NODE_REGIONis required as soon aschecksis in the list.- Every single-value spelling keeps its exact historic behavior, so existing deployments need no change.
SP_NODE_NAME pins the identity a node registers under. By default the slug
is the OS hostname, lowercased and cut to 15 characters, and it must match
^[a-z0-9][a-z0-9-]{2,20}$ (a leading digit is fine, so Docker's default
hex container-ID hostname works out of the box). Registration is an upsert on that slug, so set
SP_NODE_NAME whenever the hostname is not stable, not unique within its
first 15 characters, or not slug-legal:
SP_NODE_NAME=solidping-eu2
Two cases where it is required rather than nice to have:
- Kubernetes with
hostNetwork: true. The pod shares the host UTS namespace, sospec.hostnameis ignored and the container sees the node name — typically dotted (eu2.example.com), which the slug pattern rejects. This is the setup you need to give check workers the node's IPv6 stack on a single-stack (IPv4-only) cluster, so an IPv6-only target can be checked at all. - Pod names that collide in the first 15 characters. Deployment-generated
names such as
solidping-checks-eu2-…andsolidping-checks-us1-…both cut down tosolidping-check, and the two workers then silently share oneworkersrow. A truncated hostname logs a WARN naming the resulting slug.
An invalid effective slug (override or hostname-derived) aborts startup with a message naming the offending value, rather than failing later against the database constraint.
SP_REGIONS names your regions declaratively: the dashboard renders
{emoji} {name} wherever a region appears (check form, results, worker
load), falling back to the raw slug for undefined regions. Set it on the
main server; it seeds the regions system parameter at startup:
SP_REGIONS='[{"slug": "default", "emoji": "🇪🇺", "name": "EU1 (default)"}, {"slug": "us-1", "emoji": "🇺🇸", "name": "US1"}]'
When unset, the stored parameter (or the built-in default region) is
used, so edits made through the API are preserved across restarts.
Check Types
| Variable | Default | Description |
|---|---|---|
SP_CHECKERS_BROWSER_CDP_URL | - | Remote headless Chrome (CDP) endpoint for browser checks, e.g. ws://browser:9222. Required in containers — the image ships no browser |
SP_CHECKERS_BROWSER_CHROME_PATH | - | Local Chrome/Chromium binary used when no CDP URL is set. Empty means "probe the usual names"; nothing is ever downloaded |
Logging
| Variable | Default | Description |
|---|---|---|
SP_LOG_LEVEL | info | Log level: debug, info, warn, error |
SP_LOG_FORMAT | text | Output format: text (key=value logfmt), json (one object per record, for log collectors), pretty (colourized, for interactive use) |
LOG_LEVEL | info | Same, but read before the configuration system loads — use it to debug startup itself |
NO_COLOR | - | Set to any value to disable coloured terminal output (no-color.org) |
FORCE_COLOR | - | Set to any value to force coloured output when the terminal is not detected as a TTY |
Authentication
| Variable | Default | Description |
|---|---|---|
SP_AUTH_JWT_SECRET | auto-generated | JWT signing secret |
SP_AUTH_REGISTRATION_EMAIL_PATTERN | - | Restrict registration by email regex |
SP_AUTH_PASSWORD_ALGORITHM | argon2id | Password hashing algorithm (argon2id or bcrypt) — see Password Hashing for cost parameters |
OAuth Providers
Set both _CLIENT_ID and _CLIENT_SECRET to enable each provider:
| Provider | Variables |
|---|---|
SP_GOOGLE_CLIENT_ID, SP_GOOGLE_CLIENT_SECRET | |
| GitHub | SP_GITHUB_CLIENT_ID, SP_GITHUB_CLIENT_SECRET |
| GitLab | SP_GITLAB_CLIENT_ID, SP_GITLAB_CLIENT_SECRET |
| Microsoft | SP_MICROSOFT_CLIENT_ID, SP_MICROSOFT_CLIENT_SECRET, SP_MICROSOFT_TENANT_ID (default common) |
| Slack | SP_SLACK_CLIENT_ID, SP_SLACK_CLIENT_SECRET |
| Discord | SP_DISCORD_CLIENT_ID, SP_DISCORD_CLIENT_SECRET |
Users can also enable TOTP two-factor authentication on their accounts. See Authentication for details.
Run Mode
| Variable | Default | Description |
|---|---|---|
SP_RUN_MODE | - | Runtime mode: test (seed test data), demo |
Public Live Demo
An optional shared, read-only demo organization anyone can sign into from the login page — a real account on a real instance, not a mock. It is off by default, so a self-hosted install is unaffected until you switch it on.
| Variable | Default | Description |
|---|---|---|
SP_DEMO_ENABLED | false | Create the demo organization, user and check catalogue, and advertise them on /api/v1/config |
SP_DEMO_ORG_SLUG | demo | The demo organization's slug |
SP_DEMO_EMAIL | demo@solidping.io | The demo account's address |
SP_DEMO_PASSWORD | demo | The demo account's password — public by design, served on /api/v1/config and shown on the login page. Never reuse a real one |
SP_DEMO_CHECK_TTL | 1h | How long a check a visitor creates survives before it is cleaned up |
SP_DEMO_CLEANUP_INTERVAL | 30m | How often the cleanup job runs |
A demo session may create a check and edit or delete its own; every other
write is refused with 403 DEMO_READ_ONLY, and the seeded catalogue is
untouchable.
Deep-linking into the demo
| Link | |
|---|---|
https://solidping.io/demo | the canonical one — use this in marketing copy, docs and emails. A one-word shortcut that only exists while demo.enabled is on |
https://solidping.io/d/login?demo=true | the address the shortcut redirects to |
https://solidping.io/d/?demo=true | the dashboard root |
https://solidping.io/d/orgs/<any-org>/login?demo=true | any organization's login page |
https://solidping.io/d/orgs/<any-org>?demo=true | any organization's dashboard |
Append ?demo=true (or ?demo=1) to any of the last four and the visitor is
signed into the demo on load, with no login form and no clicks. The
organization named in the path is irrelevant: the flag always signs into the
configured demo organization. It also outranks a session the visitor
already holds — following the link from your own organization puts you in the
demo, and following it while already in the demo simply takes you there without
signing in again. Replace solidping.io with your own host on a self-hosted
install.
Encryption
| Variable | Default | Description |
|---|---|---|
SP_ENCRYPTION_MASTER_KEY | - | Base64-encoded 32-byte key for credential encryption at rest |
SP_ENCRYPTION_MASTER_KEY_FILE | - | Path to a file holding the base64 master key |
SP_ENCRYPTION_AUTO_MIGRATE | true | Encrypt existing plaintext credentials on startup |
See Security & Encryption for the full guide.
File Storage
| Variable | Default | Description |
|---|---|---|
SP_FILESTORAGE_TYPE | local | Backend: local or s3 |
SP_FILESTORAGE_LOCAL_ROOT | ./data/files | Local backend root — must be a mounted volume in a container, or uploads are lost on the next restart |
SP_FILESTORAGE_S3_BUCKET | - | S3 bucket name (required when SP_FILESTORAGE_TYPE=s3) |
SP_FILESTORAGE_S3_REGION | - | S3 region — required by the SDK even for stores that ignore it |
SP_FILESTORAGE_S3_ENDPOINT | - | Custom endpoint for S3-compatible stores (MinIO, OVHcloud, …). Empty = AWS S3 |
See File Storage for the full backend guide, S3 credential resolution, and worked examples.
Product Analytics
Analytics is off by default — with no project API key set, the server sends nothing and the dashboard loads no analytics code whatsoever.
| Variable | Default | Description |
|---|---|---|
SP_POSTHOG_PROJECT_API_KEY | - | Public phc_… PostHog browser key. Empty = analytics entirely off |
SP_POSTHOG_HOST | https://eu.i.posthog.com | PostHog ingestion endpoint |
SP_POSTHOG_PERSONAL_API_KEY | - | Optional server-side key (stored as a secret, never sent to the browser) |
SP_POSTHOG_ENABLED | true | Kill switch — never enables anything on its own |
See Product Analytics for exactly what is and is not sent.
Observability
| Variable | Default | Description |
|---|---|---|
SP_PROMETHEUS_ENABLED | true | Enable the Prometheus /metrics endpoint |
SP_PROMETHEUS_PATH | /metrics | Metrics endpoint path |
SP_SENTRY_DSN | - | Sentry DSN for error tracking |
SP_OTEL_ENABLED | false | Enable OpenTelemetry export |
SP_OTEL_ENDPOINT | - | OTLP collector endpoint |
See Observability for Sentry and OpenTelemetry details.
Development
| Variable | Description |
|---|---|
SP_REDIRECTS | Dev proxy redirects (format: /path:host:port/target,...) |
Example Configuration
Environment Variables
# Database (PostgreSQL)
SP_DB_TYPE=postgres
SP_DB_URL=postgresql://solidping:password@localhost:5432/solidping?sslmode=disable
# Server
SP_BASE_URL=https://monitoring.example.com
SP_SERVER_LISTEN=:4000
# Workers
SP_SERVER_JOB_WORKER_NB=4
SP_SERVER_CHECK_WORKER_NB=8
# Authentication
SP_AUTH_JWT_SECRET=your-secure-random-secret
SP_GOOGLE_CLIENT_ID=your-google-client-id
SP_GOOGLE_CLIENT_SECRET=your-google-client-secret
# Logging
SP_LOG_LEVEL=info
SP_LOG_FORMAT=text
Configuration File (config.yml)
db:
type: postgres
url: postgresql://solidping:password@localhost:5432/solidping?sslmode=disable
base_url: https://monitoring.example.com
server:
listen: ":4000"
job_worker_nb: 4
check_worker_nb: 8
shutdown_timeout: 30s
auth:
jwt_secret: your-secure-random-secret
email:
enabled: true
host: smtp.example.com
port: 587
username: noreply@example.com
password: smtp-password
from: noreply@example.com
from_name: SolidPing
slack:
app_id: your-slack-app-id
client_id: your-slack-client-id
client_secret: your-slack-client-secret
signing_secret: your-slack-signing-secret
CLI Configuration
The SolidPing CLI client (sp) uses its own configuration:
| Variable | Default | Description |
|---|---|---|
SOLIDPING_CONFIG | ~/.config/solidping/settings.json | CLI config file path |
SOLIDPING_URL | - | Server URL override |
SOLIDPING_ORG | - | Organization override |
SOLIDPING_VERBOSE | false | Verbose CLI logging |
Sections
- Database Configuration - PostgreSQL and SQLite options
- Notifications - Email, Slack, Discord, webhooks, and more
- Authentication - OAuth providers, 2FA, and access control
- Security & Encryption - Credentials encryption at rest
- File Storage - Where uploaded blobs (org logos, status-page assets, screenshots) are stored, and the container volume trap
- Product Analytics - Optional PostHog integration, off unless configured
- Data Retention - How long raw results and summaries are kept, and how to tune it
Security Recommendations
Always change these in production:
- Set
SP_AUTH_JWT_SECRETto a strong random value - Database passwords - Use strong, unique passwords
- Set
SP_BASE_URLto your public URL - Email credentials - Store securely, never commit to version control