services: sofarr: image: docker.i3omb.com/sofarr:latest container_name: sofarr restart: unless-stopped ports: - "127.0.0.1:3001:3001" # bind to loopback only — expose via reverse proxy environment: - PORT=3001 - NODE_ENV=production - LOG_LEVEL=info # Set to 1 when running behind a reverse proxy (Nginx, Caddy, Traefik) # so Express trusts X-Forwarded-For and X-Forwarded-Proto headers. - TRUST_PROXY=1 # --- Replace placeholders with real values or use Docker secrets --- - COOKIE_SECRET=change-me-generate-with-openssl-rand-hex-32 - EMBY_URL=https://emby.example.com - EMBY_API_KEY=your-emby-api-key - SONARR_INSTANCES=[{"name":"main","url":"https://sonarr.example.com","apiKey":"your-sonarr-api-key"}] - RADARR_INSTANCES=[{"name":"main","url":"https://radarr.example.com","apiKey":"your-radarr-api-key"}] - SABNZBD_INSTANCES=[{"name":"main","url":"https://sabnzbd.example.com","apiKey":"your-sabnzbd-api-key"}] - QBITTORRENT_INSTANCES=[{"name":"main","url":"https://qbittorrent.example.com","username":"admin","password":"your-password"}] volumes: # Persistent volume for SQLite token store and log file - sofarr-data:/app/data # Run as the built-in non-root 'node' user (UID/GID 1000) user: "1000:1000" # Read-only root filesystem; only the data volume is writable read_only: true tmpfs: - /tmp # Node.js needs a writable /tmp security_opt: - no-new-privileges:true # prevent privilege escalation via setuid binaries cap_drop: - ALL # drop all Linux capabilities cap_add: [] # add back none — Node.js needs no special caps healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:3001/health"] interval: 30s timeout: 5s retries: 3 start_period: 10s volumes: sofarr-data: