Reverse Proxy Configuration (Nginx, Caddy, Traefik, Apache)
For a production deployment of LockMyCal, we recommend placing the application behind a reverse proxy server (e.g. Caddy, Nginx, Traefik or Apache). The reverse proxy provides:
- Automatic issuing and renewal of HTTPS / SSL certificates (Let's Encrypt).
- Critically important WebSocket support for Elixir / Phoenix LiveView.
- Forwarding the correct client IP addresses (
X-Forwarded-For).
Important
LockMyCal uses Phoenix LiveView for a reactive real-time interface. Your reverse proxy MUST have WebSocket connection forwarding configured correctly (the Upgrade and Connection headers).
Tip
Do you run the application under several hostnames? List them all in WS_ALLOWED_ORIGINS. If the instance is reachable only from an internal network and visitors have private IP addresses, set TRUST_PRIVATE_CLIENT_IPS=true – otherwise everyone would share a single request limit. Don't turn this option on for a publicly accessible instance.
Option A: Caddy (Recommended for simplicity)
Caddy manages SSL certificates automatically and supports WebSockets natively without any special configuration:
bookings.yourdomain.com {
reverse_proxy localhost:4000
}
Option B: Nginx
A complete virtual host configuration for Nginx with WebSocket and HTTP/2 support:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name bookings.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name bookings.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/bookings.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/bookings.yourdomain.com/privkey.pem;
client_max_body_size 20M;
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
# WebSocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Headers for correct identification of the client and protocol
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;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
Option C: Traefik (Docker Labels)
In the docker-compose.yml file, add to the LockMyCal service:
labels:
- "traefik.enable=true"
- "traefik.http.routers.lockmycal.rule=Host(`bookings.yourdomain.com`)"
- "traefik.http.routers.lockmycal.entrypoints=websecure"
- "traefik.http.routers.lockmycal.tls.certresolver=myresolver"
- "traefik.http.services.lockmycal.loadbalancer.server.port=4000"
Option D: Apache HTTP Server
Enable the modules: a2enmod proxy proxy_http proxy_wstunnel ssl rewrite headers
<VirtualHost *:443>
ServerName bookings.yourdomain.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/bookings.yourdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/bookings.yourdomain.com/privkey.pem
# WebSocket forwarding
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://127.0.0.1:4000/$1" [P,L]
ProxyPass / http://127.0.0.1:4000/
ProxyPassReverse / http://127.0.0.1:4000/
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
</VirtualHost>