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.
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.
- 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
} - 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 usingreverse_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
} - Forward the client IP
Mastodon needs to know the original visitor IP for rate limiting and logging. Add thetrusted_proxiesdirective to tell Caddy to trust itself and pass the real IP via headers.example.com {
trusted_proxies private_ranges
reverse_proxy localhost:3000
} - 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
} - 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
} - 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
}
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.