Mastodon Instance Reverse Proxy With Caddy: Configuration Notes
🔍 WiseChecker

Mastodon Instance Reverse Proxy With Caddy: Configuration Notes

Running a Mastodon instance requires a reverse proxy to handle TLS termination, request routing, and WebSocket support. Caddy is a modern web server that simplifies this process with automatic HTTPS and a clean configuration syntax. Many administrators choose Caddy because it eliminates the need to manually manage SSL certificates. This article explains the key settings needed to configure Caddy as a reverse proxy for a Mastodon instance, including WebSocket support, client body size limits, and security headers.

Key Takeaways: Caddy Reverse Proxy Settings for Mastodon

  • reverse_proxy directive with trusted_proxies: Ensures Caddy forwards the correct client IP to the Mastodon backend.
  • request_body /max_size 10MB: Prevents upload errors for media attachments that exceed the default limit.
  • header_up X-Forwarded-Proto {scheme}: Passes the original protocol (HTTP or HTTPS) so Mastodon generates correct URLs.

ADVERTISEMENT

Why Mastodon Needs a Reverse Proxy

Mastodon is a Ruby on Rails application that runs an internal web server on a non-privileged port. This server is not designed to handle public traffic directly for several reasons. First, it lacks TLS support, meaning all traffic would be unencrypted. Second, it cannot serve static assets as efficiently as a dedicated web server. Third, Mastodon uses WebSocket connections for real-time streaming of timelines, which require persistent connections that a reverse proxy can manage.

Caddy automatically provisions and renews Let’s Encrypt certificates, making TLS setup trivial. It also handles HTTP/2 and HTTP/3, compresses responses, and adds security headers. By placing Caddy in front of Mastodon, you offload all these tasks from the application server, allowing it to focus on delivering content.

Essential Caddy Configuration for Mastodon

The core of the configuration is the reverse_proxy directive inside a site block. Below is a minimal working example. Replace example.com with your actual domain and localhost:3000 with your Mastodon web process address if different.

  1. Set up the site block
    Create a Caddyfile entry for your domain. Caddy will automatically obtain a TLS certificate on first request.
    example.com {
    reverse_proxy localhost:3000
    }
  2. Add WebSocket support
    Mastodon uses WebSockets for the streaming API. Without this, features like live timeline updates will not work. Caddy handles WebSocket upgrades automatically when using reverse_proxy, but you must ensure the backend address is correct. The streaming server usually runs on port 4000. Add a separate reverse proxy for the streaming endpoint.
    example.com {
    reverse_proxy /api/v1/streaming/ localhost:4000
    reverse_proxy localhost:3000
    }
  3. Forward the client IP
    Mastodon needs to know the original visitor IP for rate limiting and logging. Add the trusted_proxies directive to tell Caddy to trust itself and pass the real IP via headers.
    example.com {
    trusted_proxies private_ranges
    reverse_proxy localhost:3000
    }
  4. Increase request body size
    Mastodon allows media uploads up to 8 MB by default, but administrators may increase this limit. Caddy’s default is 1 MB. Set the maximum body size to at least 10 MB to avoid upload failures.
    example.com {
    request_body /max_size 10MB
    reverse_proxy localhost:3000
    }
  5. Add security headers
    Security headers protect against common web attacks. The following headers are recommended for Mastodon instances.
    example.com {
    header / {
    X-Content-Type-Options "nosniff"
    X-Frame-Options "DENY"
    X-XSS-Protection "1; mode=block"
    Referrer-Policy "strict-origin-when-cross-origin"
    }
    reverse_proxy localhost:3000
    }
  6. Enable gzip compression
    Compression reduces bandwidth and speeds up page loads. Caddy enables gzip by default, but you can explicitly configure it if needed.
    example.com {
    encode gzip
    reverse_proxy localhost:3000
    }

ADVERTISEMENT

Common Configuration Mistakes

WebSocket connections fail after a few seconds

If WebSocket connections drop repeatedly, the reverse proxy for the streaming endpoint is likely missing or misconfigured. Ensure the path /api/v1/streaming/ is routed to port 4000. Also verify that Caddy is not applying timeouts that are too short. Add reverse_proxy /api/v1/streaming/ localhost:4000 before the general reverse proxy line. Caddy evaluates routes in order, so the streaming path must match first.

Media uploads return 413 Request Entity Too Large

This error indicates the request body size limit is too low. Caddy’s default is 1 MB, while Mastodon’s default is 8 MB. Increase the limit to at least 10 MB using the request_body /max_size directive. If you raised Mastodon’s limit further, set the Caddy limit to match.

Client IP shows as 127.0.0.1 in logs

Without the trusted_proxies directive, Caddy does not forward the original client IP. Add trusted_proxies private_ranges to your Caddyfile. This tells Caddy to trust IPs from private ranges and pass the real IP via the X-Forwarded-For header. Mastodon must also be configured to read this header. In .env.production, set TRUSTED_PROXY_IPS=127.0.0.1 or the IP of your Caddy container.

Item Nginx Caddy
Description Traditional reverse proxy with manual SSL certificate management Modern reverse proxy with automatic HTTPS and simpler configuration
SSL certificate renewal Manual or via certbot cron job Automatic via Let’s Encrypt
Configuration syntax Directive-based with many nested blocks Concise, declarative directives
WebSocket support Requires explicit proxy_set_header Upgrade and Connection directives Automatic when using reverse_proxy
Request body size limit client_max_body_size 10M request_body /max_size 10MB
Client IP forwarding proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for trusted_proxies private_ranges

With the configuration steps above, your Mastodon instance will run efficiently behind Caddy. The automatic TLS feature eliminates certificate renewal worries, and the security headers protect against common vulnerabilities. To verify everything is working, check the Mastodon logs for the correct client IP and test media uploads of various sizes. If you need to scale, consider adding Caddy’s built-in load balancing with multiple Mastodon web processes.

ADVERTISEMENT