Reverse proxy
Put Savvy behind HTTPS with Traefik or Nginx Proxy Manager. Forwarded-header handling means HTTPS links and real client IPs work with no extra config.
Run Savvy behind a reverse proxy to terminate TLS and serve it on your own
domain. Set APP_URL to your public https:// URL — Savvy honors the
X-Forwarded-Proto and X-Forwarded-For headers from the proxy, so HTTPS link
generation and real client IPs work automatically, with no extra configuration.
Always set APP_URL to the public HTTPS URL
Behind a proxy the app sees plain HTTP internally. APP_URL is what tells it
the real external scheme and host. If it's wrong, redirects loop and logins
fail.
Traefik handles routing and Let's Encrypt certificates via container labels:
services: savvy: image: truenormis/savvy:v1.2.3 container_name: savvy restart: unless-stopped volumes: - savvy-data:/data environment: - APP_URL=https://savvy.yourdomain.com - TZ=Europe/Kyiv labels: - "traefik.enable=true" - "traefik.http.routers.savvy.rule=Host(`savvy.yourdomain.com`)" - "traefik.http.routers.savvy.entrypoints=websecure" - "traefik.http.routers.savvy.tls.certresolver=letsencrypt" - "traefik.http.services.savvy.loadbalancer.server.port=80" networks: - traefikvolumes: savvy-data:networks: traefik: external: trueThis assumes an existing external traefik network and a websecure
entrypoint with a letsencrypt cert resolver already configured on your Traefik
instance.
Expose the container on the internal network only, then point a proxy host at it from the NPM UI:
services: savvy: image: truenormis/savvy:v1.2.3 container_name: savvy restart: unless-stopped expose: - "80" volumes: - savvy-data:/data environment: - APP_URL=https://savvy.yourdomain.com networks: - npm-networkvolumes: savvy-data:networks: npm-network: external: trueIn Nginx Proxy Manager, create a Proxy Host with:
- Forward Hostname / IP:
savvy - Forward Port:
80 - Scheme:
http - Enable Block Common Exploits and request an SSL certificate on the SSL tab.
Community example — verify before use
This raw nginx block is a typical configuration, not copied from the project's docs. Adjust paths and your TLS setup, and test before relying on it.
If you terminate TLS with a standalone nginx, proxy to the container and pass the forwarded headers Savvy expects:
server {
listen 443 ssl;
server_name savvy.yourdomain.com;
# ssl_certificate /etc/letsencrypt/live/savvy.yourdomain.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/savvy.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}Installation
Install Savvy with Docker Compose — persistent volume, environment variables and health-check endpoints for a production-ready self-hosted expense tracker.
Kubernetes
Deploy Savvy on Kubernetes as a single-replica Deployment with a PersistentVolumeClaim and liveness/readiness probes wired to the health endpoints.