Repository navigation
Troubleshooting
Config is validated fail-fast — the message names the exact variable and
why it's invalid. Run shortr config check to see the full resolved config
without starting the server. Common ones:
-
SHORTR_BASE_URL: invalid URL— must include a scheme (http:///https://), no trailing content beyond host[:port]. -
SHORTR_DB_DSN is required when SHORTR_DB_DRIVER=postgres— set a full Postgres connection string. -
SHORTR_SECRET_KEY must be at least 32 characters— either remove it (let Shortr auto-generate one) or use a longer value, e.g.openssl rand -hex 32. -
SHORTR_OIDC_ISSUER must be https— either use an HTTPS issuer or setSHORTR_OIDC_INSECURE_HTTP=truefor local testing only.
The process is up but the database isn't reachable. For SQLite, check
SHORTR_DATA_DIR is writable and not on a network filesystem that doesn't
support proper file locking. For Postgres, check SHORTR_DB_DSN,
network/firewall rules, and that the Postgres container/service is actually
healthy (docker compose ps).
SHORTR_TRUSTED_PROXIES isn't set (or doesn't include your proxy), so
Shortr is trusting the TCP peer address instead of X-Forwarded-For — which
is your reverse proxy's own IP for every request. Set it to your proxy's
address or the Docker network CIDR it lives on. See
Deployment.
Check which limiter: the response includes a Retry-After header. If it's
happening for legitimate traffic behind a shared NAT/proxy IP, the same
TRUSTED_PROXIES misconfiguration above is often the cause — traffic that
should be attributed per-user/per-real-IP is instead bucketed under one IP.
Otherwise, raise the relevant SHORTR_RATE_LIMIT_* variable.
- Check Admin → Settings (or
SHORTR_SMTP_ENABLED/SHORTR_GOTIFY_ENABLED) is actually on. - Notification delivery is best-effort and logged, not surfaced to the UI as
an error — check server logs (
SHORTR_LOG_LEVEL=debugfor more detail) forsmtp dial:/smtp auth:/ Gotify HTTP errors. - SMTP sends have a 10s timeout; a consistently slow/unreachable host will show timeout errors in the log rather than hanging the server.
Click writes are batched and asynchronous by design (so the redirect path
never blocks on a database write). On a database outage, batches are
spooled to <DATA_DIR>/clicks-spool/*.jsonl and automatically replayed on
next startup — check the log for replayed spooled clicks. On a graceful
shutdown (SIGTERM), the writer is given up to SHORTR_SHUTDOWN_TIMEOUT to
flush before the process exits.
Neither a GeoIP database nor the IP location service is configured. Client IPs on loopback/private ranges are never located. If the service is set: it must return the documented JSON at GET <base>/<ip>, and after an error the same IP isn't retried for a minute. For a .mmdb: SHORTR_GEOIP_DB isn't set, or points to a file that failed to open — check
startup logs for GeoIP database could not be opened. Download a
GeoLite2-City .mmdb from MaxMind (free account required) and point
SHORTR_GEOIP_DB at it.
Shortr is behind a proxy or tunnel and SHORTR_TRUSTED_PROXIES doesn't include it. Also check SHORTR_IP_MODE — the default anonymize zeroes the last octet; use full to store exact addresses.
An admin needs to enable it first: Admin → Settings → MCP Server. See MCP Server.
Open an issue with: shortr version output, relevant log lines (redact
secrets/tokens), and your SHORTR_* config with secrets stripped
(shortr config check already masks them).