SesameSesame

Reverse Proxies

Securely expose Sesame with HTTPS using reverse proxies and tunnels

A reverse proxy terminates TLS and provides HTTPS access to Sesame. This guide covers popular options for self-hosted environments.

Traditional Reverse Proxies

These run alongside Sesame on your server and handle TLS termination, load balancing, and routing.

nginx

nginx is a battle-tested option with wide community support.

/etc/nginx/sites-available/sesame
server {
    listen 80;
    server_name sesame.example.com;
    return 301 https://$server_name$request_uri;
}

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

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

    # Modern TLS configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    location / {
        proxy_pass http://localhost:13531;
        proxy_http_version 1.1;

        # Required for WebSocket connections
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_cache_bypass $http_upgrade;

        # Required for SSE (Server-Sent Events) streaming
        proxy_buffering off;
        proxy_read_timeout 86400s;

        # Forward client info
        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;
    }
}

Enable the site and reload nginx:

sudo ln -s /etc/nginx/sites-available/sesame /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Use Certbot to automatically obtain and renew Let's Encrypt certificates.

Caddy

Caddy automatically provisions TLS certificates from Let's Encrypt with zero configuration.

Caddyfile
sesame.example.com {
    reverse_proxy localhost:13531 {
        # Disable buffering for SSE streaming
        flush_interval -1
    }
}

That's it! Caddy handles HTTPS automatically. Run with:

caddy run

Or use Docker Compose alongside Sesame:

docker-compose.yml
services:
  sesame:
    image: ghcr.io/jakejarvis/sesame:latest
    # ... your existing config

  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
      - caddy-config:/config

volumes:
  caddy-data:
  caddy-config:

Traefik

Traefik automatically discovers services via Docker labels and provisions certificates.

docker-compose.yml
services:
  traefik:
    image: traefik:v3.4
    restart: unless-stopped
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.letsencrypt.acme.email=admin@example.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "./letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

  sesame:
    image: ghcr.io/jakejarvis/sesame:latest
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.sesame.rule=Host(`sesame.example.com`)"
      - "traefik.http.routers.sesame.entrypoints=websecure"
      - "traefik.http.routers.sesame.tls.certresolver=letsencrypt"
      - "traefik.http.services.sesame.loadbalancer.server.port=13531"
    volumes:
      - sesame-data:/app/data
      - sesame-sandboxes:/app/sandboxes
    environment:
      BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
      BASE_URL: https://sesame.example.com
      ENCRYPTION_KEY: ${ENCRYPTION_KEY}

volumes:
  sesame-data:
  sesame-sandboxes:

Update admin@example.com with your email for Let's Encrypt notifications.

These options are the safest way to access Sesame from anywhere without opening ports on your firewall or configuring DNS. They create outbound-only connections to edge networks that proxy traffic to your local service.

Tailscale Funnel

Tailscale Funnel exposes your local Sesame instance to the internet through Tailscale's network. No open ports, no firewall rules, automatic HTTPS.

Advantages:

  • Zero firewall configuration (outbound connections only)
  • Automatic TLS certificates
  • Built-in access controls via Tailscale ACLs
  • Works behind NAT, CGNAT, and corporate firewalls

Quick Setup

  1. Install Tailscale on the machine running Sesame

  2. Enable Funnel in your Tailscale admin console under DNS > Funnel

  3. Start Sesame with Funnel:

# Expose Sesame on port 443 (recommended)
tailscale funnel --bg 13531

Your instance is now available at https://<machine-name>.<tailnet-name>.ts.net

Docker Setup

Run Tailscale as a sidecar container:

docker-compose.yml
services:
  tailscale:
    image: tailscale/tailscale:latest
    hostname: sesame
    environment:
      - TS_AUTHKEY=${TS_AUTHKEY} # Generate at https://login.tailscale.com/admin/settings/keys
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_SERVE_CONFIG=/config/serve.json
    volumes:
      - tailscale-state:/var/lib/tailscale
      - ./tailscale:/config
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    restart: unless-stopped

  sesame:
    image: ghcr.io/jakejarvis/sesame:latest
    network_mode: service:tailscale
    depends_on:
      - tailscale
    volumes:
      - sesame-data:/app/data
      - sesame-sandboxes:/app/sandboxes
    environment:
      BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
      BASE_URL: https://sesame.<tailnet-name>.ts.net
      ENCRYPTION_KEY: ${ENCRYPTION_KEY}

volumes:
  tailscale-state:
  sesame-data:
  sesame-sandboxes:
tailscale/serve.json
{
  "TCP": {
    "443": {
      "HTTPS": true
    }
  },
  "Web": {
    "sesame.<tailnet-name>.ts.net:443": {
      "Handlers": {
        "/": {
          "Proxy": "http://127.0.0.1:13531"
        }
      }
    }
  },
  "AllowFunnel": {
    "sesame.<tailnet-name>.ts.net:443": true
  }
}
Replace <tailnet-name> with your Tailscale tailnet name (found in admin console).

Cloudflare Tunnel

Cloudflare Tunnel (formerly Argo Tunnel) creates a secure outbound connection from your server to Cloudflare's edge network.

Advantages:

  • No open inbound ports required
  • Automatic TLS with your own domain
  • DDoS protection included
  • Can add Cloudflare Access for additional authentication

Prerequisites

  • A domain on Cloudflare (free plan works)
  • cloudflared CLI installed

Quick Setup

  1. Authenticate with Cloudflare:
cloudflared tunnel login
  1. Create a tunnel:
cloudflared tunnel create sesame
  1. Create the config file:
~/.cloudflared/config.yml
tunnel: <TUNNEL-UUID>
credentials-file: /root/.cloudflared/<TUNNEL-UUID>.json

ingress:
  - hostname: sesame.example.com
    service: http://localhost:13531
    originRequest:
      noTLSVerify: true
  - service: http_status:404
  1. Route DNS to the tunnel:
cloudflared tunnel route dns sesame sesame.example.com
  1. Run the tunnel:
cloudflared tunnel run sesame

Docker Setup

docker-compose.yml
services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    restart: unless-stopped
    command: tunnel run
    environment:
      - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}

  sesame:
    image: ghcr.io/jakejarvis/sesame:latest
    restart: unless-stopped
    volumes:
      - sesame-data:/app/data
      - sesame-sandboxes:/app/sandboxes
    environment:
      BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}
      BASE_URL: https://sesame.example.com
      ENCRYPTION_KEY: ${ENCRYPTION_KEY}

volumes:
  sesame-data:
  sesame-sandboxes:

Get your CLOUDFLARE_TUNNEL_TOKEN from the Zero Trust dashboard under Networks > Tunnels > Create a tunnel.

Comparison

Featurenginx/Caddy/TraefikTailscale FunnelCloudflare Tunnel
Open ports requiredYes (80, 443)NoNo
Custom domainYesNo (uses ts.net)Yes
Auto TLSCaddy/Traefik onlyYesYes
Works behind NATNoYesYes
DDoS protectionNoLimitedYes
Setup complexityMediumLowMedium
CostFreeFreeFree

Security Recommendations

  1. Always use HTTPS - Never expose Sesame over plain HTTP
  2. Set BASE_URL - Must match your public URL for auth to work correctly
  3. Use strong secrets - Generate BETTER_AUTH_SECRET with openssl rand -base64 32 and ENCRYPTION_KEY with openssl rand -hex 32
  4. Consider access controls - Use Tailscale ACLs or Cloudflare Access to restrict who can reach your instance
  5. Keep software updated - Regularly update Sesame, your reverse proxy, and tunnel software

On this page