This page provides configuration for setting up an external reverse proxy with Plane.
Plane environment setup
Make sure to update the following environment variables in your plane.env file.
Assign free ports for Plane to listen on. Update the following variables with two different unsused ports:
LISTEN_HTTP_PORT =
LISTEN_HTTPS_PORT =
Update the SITE_ADDRESS variable to :80
This is required so that generated links and redirects work correctly behind the proxy:
Proxy setup
Choose the appropriate configuration template for your reverse proxy.
Replace the following placeholders:
<domain>
Your Plane application’s domain name.
<plane-host-ip>
The IP address where Plane is hosted.
<plane-host-port>
The port Plane listens on.
For Traefik, also update your-email@example.com
with your email.
Ensure that your reverse proxy setup follows the template provided, and that the forwarded headers and ports are correctly set to match the environment variable configuration.
Configuration templates
All configurations include:
Automatic HTTPS redirection
WebSocket support
Standard proxy headers
SSL/TLS certificate management
NGINX: Uses Certbot
Caddy: Handles certificates automatically
Traefik: Uses Let’s Encrypt
server {
server_name < domai n > ;
location / {
proxy_pass http:// < plane-host-i p > : < plane-host-por t > / ;
# Set headers for proxied request
proxy_set_header X-Forwarded-Proto $scheme ;
proxy_set_header X-Forwarded-Host $host ;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;
proxy_set_header X-Real-IP $remote_addr ;
proxy_set_header Upgrade $http_upgrade ;
proxy_set_header Connection "upgrade" ;
proxy_set_header Host $http_host ;
proxy_http_version 1.1 ;
}
client_max_body_size 10M ;
listen 443 ssl ; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/ < domai n > /fullchain.pem ;
ssl_certificate_key /etc/letsencrypt/live/ < domai n > /privkey.pem ;
include /etc/letsencrypt/options-ssl-nginx.conf ;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem ;
}
server {
if ( $host = < domain > ) {
return 301 https:// $host$request_uri ;
}
listen 80 ;
server_name < domai n > ;
return 404 ;
}
< domain > {
tls {
# Caddy will automatically handle certificates
}
redir / https://{host}{uri} permanent
reverse_proxy < plane-host-i p > : < plane-host-por t > {
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up Host {http.request.host}
header_up Upgrade {http.request.header.Upgrade}
header_up Connection {http.request.header.Connection}
transport http {
tls_insecure_skip_verify
read_buffer 4096
write_buffer 4096
}
}
request_body {
max_size 10MB
}
}
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: your-email@example.com # Replace with your email
storage: acme.json
httpChallenge:
entryPoint: web
providers:
http:
routers:
plane-router:
rule: "Host(` < domain > `)"
service: plane-service
entryPoints:
- websecure
tls:
certResolver: letsencrypt
services:
plane-service:
loadBalancer:
servers:
- url: "http://<plane-host-ip>:<plane-host-port>"
passHostHeader: true
responseForwarding:
flushInterval: "100ms"
serversTransport:
maxIdleConnsPerHost: 100
forwardingTimeouts:
dialTimeout: 30s
responseHeaderTimeout: 30s
idleConnTimeout: 90s
middlewares:
headers:
headers:
customRequestHeaders:
X-Forwarded-Proto: "https"
X-Real-IP: "{{ .RemoteAddr }}"