Reverse proxy setup
Set up a reverse proxy to access your Kurpod server securely over HTTPS, enable custom domains, and add additional security layers. This guide covers popular reverse proxy configurations.
Why use a reverse proxy?
A reverse proxy provides several benefits:
- HTTPS encryption: Secure connection between client and proxy
- Custom domain: Access via
files.yourdomain.com
- Additional security: Rate limiting, IP filtering, DDoS protection
- Load balancing: Distribute traffic across multiple servers
- Caching: Improve performance for static assets
- Hide origin: Conceal actual server location
End-to-end encryption
Kurpod already encrypts all data client-side. The reverse proxy adds transport security (HTTPS) but doesn't see your decrypted files.
Nginx configuration
Basic HTTPS setup
Install Nginx and configure for Kurpod:
# /etc/nginx/sites-available/kurpod
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name files.yourdomain.com;
# SSL configuration
ssl_certificate /etc/letsencrypt/live/files.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/files.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Proxy settings
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
# WebSocket support
proxy_read_timeout 86400;
}
# Increase upload size for large files
client_max_body_size 5G;
proxy_request_buffering off;
}
# Redirect HTTP to HTTPS
server {
listen 80;
listen [::]:80;
server_name files.yourdomain.com;
return 301 https://$server_name$request_uri;
}
Advanced Nginx features
Rate limiting
# Define rate limit zone
limit_req_zone $binary_remote_addr zone=kurpod:10m rate=10r/s;
# Apply to location
location / {
limit_req zone=kurpod burst=20 nodelay;
proxy_pass http://localhost:3000;
}
IP whitelisting
# Allow only specific IPs
location / {
allow 192.168.1.0/24;
allow 10.0.0.0/8;
deny all;
proxy_pass http://localhost:3000;
}
Caching static assets
# Cache static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
proxy_pass http://localhost:3000;
proxy_cache_valid 200 1d;
proxy_cache kurpod_cache;
add_header X-Cache-Status $upstream_cache_status;
}
SSL with Let's Encrypt
Automate SSL certificate management:
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Obtain certificate
sudo certbot --nginx -d files.yourdomain.com
# Auto-renewal is configured automatically
# Test renewal
sudo certbot renew --dry-run
Apache configuration
Basic setup
Configure Apache as reverse proxy:
# /etc/apache2/sites-available/kurpod.conf
<VirtualHost *:443>
ServerName files.yourdomain.com
# Enable modules
# a2enmod proxy proxy_http proxy_wstunnel ssl headers
# SSL configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/files.yourdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/files.yourdomain.com/privkey.pem
SSLProtocol -all +TLSv1.2 +TLSv1.3
# Security headers
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
# Proxy configuration
ProxyRequests Off
ProxyPreserveHost On
# WebSocket proxy
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://localhost:3000/$1" [P,L]
# HTTP proxy
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
# Large file support
LimitRequestBody 5368709120
</VirtualHost>
# HTTP to HTTPS redirect
<VirtualHost *:80>
ServerName files.yourdomain.com
Redirect permanent / https://files.yourdomain.com/
</VirtualHost>
Apache security
ModSecurity WAF
# Install ModSecurity
sudo apt install libapache2-mod-security2
# Enable in VirtualHost
<IfModule mod_security2.c>
SecRuleEngine On
SecRequestBodyLimit 5368709120
SecRequestBodyNoFilesLimit 65536
</IfModule>
Access control
# IP-based restrictions
<Location />
Require ip 192.168.1.0/24
Require ip 10.0.0.0/8
</Location>
Caddy configuration
Simple setup
Caddy provides automatic HTTPS:
# /etc/caddy/Caddyfile
files.yourdomain.com {
# Automatic HTTPS with Let's Encrypt
# Reverse proxy
reverse_proxy localhost:3000 {
# WebSocket support
header_up Upgrade {http.request.header.Upgrade}
header_up Connection {http.request.header.Connection}
}
# Security headers
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
-Server
}
# Large uploads
request_body {
max_size 5GB
}
}
Advanced Caddy features
Rate limiting
files.yourdomain.com {
rate_limit {
zone dynamic {
key {remote_host}
events 100
window 1m
}
}
reverse_proxy localhost:3000
}
Basic authentication
files.yourdomain.com {
basicauth /* {
admin $2a$14$5iLmVCdR.J3qHzs.k0mYpeD3gqKHqKJ8oD5Zc1yQoGDVkqD3hvwNa
}
reverse_proxy localhost:3000
}
Traefik configuration
Docker setup
For containerized deployments:
# docker-compose.yml
version: '3.8'
services:
traefik:
image: traefik:v2.9
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik.yml:/traefik.yml
- ./acme.json:/acme.json
labels:
- "traefik.http.routers.api.rule=Host(`traefik.yourdomain.com`)"
- "traefik.http.routers.api.service=api@internal"
kurpod:
image: ghcr.io/srv1n/kurpod-server:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.kurpod.rule=Host(`files.yourdomain.com`)"
- "traefik.http.routers.kurpod.entrypoints=websecure"
- "traefik.http.routers.kurpod.tls.certresolver=letsencrypt"
- "traefik.http.services.kurpod.loadbalancer.server.port=3000"
volumes:
- ./blobs:/app/blobs
Traefik configuration
# traefik.yml
api:
dashboard: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: acme.json
httpChallenge:
entryPoint: web
providers:
docker:
exposedByDefault: false
Security best practices
Headers configuration
Essential security headers for all proxies:
// Required headers
{
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
"X-Frame-Options": "SAMEORIGIN",
"X-Content-Type-Options": "nosniff",
"X-XSS-Protection": "1; mode=block",
"Referrer-Policy": "strict-origin-when-cross-origin",
"Permissions-Policy": "geolocation=(), microphone=(), camera=()"
}
DDoS protection
Cloudflare integration
# Trust Cloudflare IPs only
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
# ... add all Cloudflare ranges
real_ip_header CF-Connecting-IP;
Rate limiting strategies
# Multiple rate limit zones
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
limit_req_zone $binary_remote_addr zone=upload:10m rate=1r/s;
# Apply different limits
location /api/auth {
limit_req zone=login burst=5 nodelay;
}
location /api/upload {
limit_req zone=upload burst=2;
}
Monitoring
Access logs
# Custom log format
log_format kurpod '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
access_log /var/log/nginx/kurpod_access.log kurpod;
Fail2ban integration
# /etc/fail2ban/jail.local
[kurpod]
enabled = true
port = https
filter = kurpod
logpath = /var/log/nginx/kurpod_access.log
maxretry = 5
bantime = 3600
Troubleshooting
Common issues
502 Bad Gateway
- Check Kurpod is running:
systemctl status kurpod
- Verify proxy_pass URL is correct
- Check firewall allows connection
WebSocket connection failed
- Ensure WebSocket headers are set
- Check timeout settings
- Verify upgrade headers are passed
SSL certificate errors
- Check certificate paths
- Verify domain DNS
- Test with
curl -v https://yourdomain.com
Testing configuration
Nginx syntax check
nginx -t
Apache syntax check
apache2ctl configtest
Test headers
curl -I https://files.yourdomain.com
WebSocket test
// Browser console
const ws = new WebSocket('wss://files.yourdomain.com/ws');
ws.onopen = () => console.log('WebSocket connected');
ws.onerror = (e) => console.error('WebSocket error:', e);
Performance optimization
Enable HTTP/2
listen 443 ssl http2;
Compression
gzip on;
gzip_types text/plain application/json application/javascript text/css;
gzip_min_length 1000;
Connection pooling
upstream kurpod_backend {
server localhost:3000;
keepalive 32;
}
Next steps
After setting up your reverse proxy, explore backup strategies to ensure your encrypted data is safely backed up, or review security best practices for additional hardening.