# Reverse Proxy When running Windshift behind a reverse proxy, configure Windshift to trust forwarded headers and restrict allowed hostnames. ## Required Settings ```bash ./windshift --use-proxy --allowed-hosts windshift.example.com --base-url https://windshift.example.com ``` Or via environment variables: ```bash export USE_PROXY=true export ALLOWED_HOSTS=windshift.example.com export BASE_URL=https://windshift.example.com ./windshift ``` | Flag | Env Var | Description | |------|---------|-------------| | `--use-proxy` | `USE_PROXY` | Trust `X-Forwarded-Proto` and `X-Forwarded-For` headers | | `--allowed-hosts` | `ALLOWED_HOSTS` | Comma-separated list of valid hostnames | | `--base-url` | `BASE_URL` | Public URL used to generate links in emails, SSO redirects, and calendar feeds | | `--allowed-port` | - | Port used for CORS and WebAuthn origin validation | | `--additional-proxies` | `ADDITIONAL_PROXIES` | Additional trusted proxy IPs beyond the default private ranges | > **Note:** `BASE_URL` should be set to the public URL users access Windshift from (e.g. `https://windshift.example.com`). Without it, email verification links, magic login links, SSO redirects, and calendar feed URLs will point at `http://localhost:8080`. > **Important:** When `--use-proxy` is enabled, Windshift trusts `X-Forwarded-For` and `X-Forwarded-Proto` headers to determine the client's real IP address and protocol. These headers can be spoofed by any client. You **must** ensure that Windshift is not directly reachable from the internet - only the reverse proxy should be able to connect to Windshift's port. Bind Windshift to `127.0.0.1` or use firewall rules / Docker networking to block external access. Otherwise, an attacker can forge these headers to bypass IP-based restrictions or trick Windshift into thinking a connection is over HTTPS when it isn't. ## Caddy Caddy provides automatic HTTPS with minimal configuration: ```text windshift.example.com { reverse_proxy localhost:8080 } ``` Caddy automatically handles TLS certificates via Let's Encrypt and sets the correct forwarded headers. ## Nginx ```nginx server { listen 443 ssl http2; server_name windshift.example.com; ssl_certificate /etc/ssl/certs/windshift.pem; ssl_certificate_key /etc/ssl/private/windshift.key; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # WebSocket support (for live updates) proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } ``` ## Traefik Using Docker labels: ```yaml services: windshift: image: ghcr.io/windshiftapp/windshift:latest environment: - USE_PROXY=true - ALLOWED_HOSTS=${DOMAIN} - BASE_URL=https://${DOMAIN} labels: - "traefik.enable=true" - "traefik.http.routers.windshift.rule=Host(`${DOMAIN}`)" - "traefik.http.routers.windshift.entrypoints=websecure" - "traefik.http.routers.windshift.tls.certresolver=letsencrypt" - "traefik.http.services.windshift.loadbalancer.server.port=8080" traefik: image: traefik:v3.4 command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - letsencrypt-data:/letsencrypt ``` ## TLS Termination If you prefer to terminate TLS at Windshift itself (without a reverse proxy), use the built-in TLS support: ```bash ./windshift --tls-cert /path/to/cert.pem --tls-key /path/to/key.pem ``` This is useful for simple deployments where an external proxy isn't needed.