Reverse proxy and TLS

Tidefetch serves HTTP and WebSocket traffic on the same port. Proxies must preserve the original Host header and support WebSocket upgrades. Tidefetch currently expects to run at the root of a hostname; a subpath such as example.com/tidefetch/ is not supported.

Security choices

Recommended:

tidefetch serve -host 127.0.0.1 -password 'a-long-unique-password'

This keeps Tidefetch authentication enabled behind the TLS proxy. If an identity-aware proxy already enforces access, -no-auth is possible, but the listener should remain on loopback or a private container network.

Never pass the aria2 RPC port through the public proxy.

Caddy

Host process:

tidefetch.example.com {
    encode zstd gzip
    reverse_proxy 127.0.0.1:8210
}

Docker network:

tidefetch.example.com {
    encode zstd gzip
    reverse_proxy tidefetch:8210
}

Caddy provisions and renews TLS automatically when public DNS points to the server and ports 80/443 are reachable.

Nginx

Add the map in the top-level http context:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

Virtual host:

server {
    listen 443 ssl http2;
    server_name tidefetch.example.com;

    ssl_certificate     /etc/letsencrypt/live/tidefetch.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tidefetch.example.com/privkey.pem;

    client_max_body_size 32m;

    location / {
        proxy_pass http://127.0.0.1:8210;
        proxy_http_version 1.1;
        proxy_set_header Host $http_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;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

The long read timeout keeps the state WebSocket alive. The upload limit permits .torrent and Metalink files without allowing unbounded request bodies.

Traefik with Compose

Attach Tidefetch to the same external network as Traefik:

services:
  tidefetch:
    image: ghcr.io/thre4dripper/tidefetch:latest
    environment:
      TIDEFETCH_PASSWORD_FILE: /run/secrets/web_password
    networks:
      - proxy
    labels:
      traefik.enable: "true"
      traefik.http.routers.tidefetch.rule: Host(`tidefetch.example.com`)
      traefik.http.routers.tidefetch.entrypoints: websecure
      traefik.http.routers.tidefetch.tls: "true"
      traefik.http.routers.tidefetch.tls.certresolver: letsencrypt
      traefik.http.services.tidefetch.loadbalancer.server.port: "8210"

networks:
  proxy:
    external: true

Traefik handles WebSocket upgrades automatically. Do not publish 8210 to the host when Traefik is the only intended entry point.

Kubernetes Ingress

The included manifest exposes a ClusterIP service named tidefetch. A generic Ingress is:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tidefetch
  namespace: tidefetch
spec:
  ingressClassName: nginx
  tls:
    - hosts: [tidefetch.example.com]
      secretName: tidefetch-tls
  rules:
    - host: tidefetch.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: tidefetch
                port:
                  number: 8210

For cert-manager, add the issuer annotation used by the cluster. Nginx Ingress supports WebSockets without service-specific annotations on current versions.

Tailscale Serve

For private tailnet access without public DNS:

tailscale serve --bg https / http://127.0.0.1:8210
tailscale serve status

Keep Tidefetch authentication enabled for defense in depth, especially when the tailnet has many users or shared devices.

Validation

Check HTTP and the WebSocket endpoint through the public hostname:

curl -I https://tidefetch.example.com/
curl -sS https://tidefetch.example.com/api/state

The state endpoint can return 401 Unauthorized before login; that proves the request reached Tidefetch. In browser developer tools, /api/ws should switch protocols with status 101 after authentication.