Hi everyone,
I know this might sound a bit strange, but I’ve spent the last three days trying to sort this out on my own, and unfortunately, I haven’t been successful. Could anyone help me migrate from Nginx to Traefik?
Background:
I have a script that prepares and deploys Nginx along with a couple of applications. The resulting Nginx config files are:
/etc/nginx/stream-enabled/stream.conf
map $ssl_preread_server_name $sni_name {
hostnames;
second_domain app;
first_domain www;
default app;
}
upstream app {
server 127.0.0.1:8443;
}
upstream www {
server 127.0.0.1:7443;
}
server {
proxy_protocol on;
set_real_ip_from unix:;
listen 443;
proxy_pass $sni_name;
ssl_preread on;
}
/etc/nginx/sites-available/80.conf
server {
listen 80;
server_name first_domain second_domain;
return 301 https://$host$request_uri;
}
/etc/nginx/sites-available/first_domain
server {
server_tokens off;
server_name first_domain;
listen 7443 ssl http2 proxy_protocol;
listen [::]:7443 ssl http2 proxy_protocol;
index index.html index.htm index.php index.nginx-debian.html;
root /var/www/html/;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!eNULL:!MD5:!DES:!RC4:!ADH:!SSLv3:!EXP:!PSK:!DSS;
ssl_certificate /etc/letsencrypt/live/first_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/first_domain/privkey.pem;
if ($host !~* ^(.+\.)?first_domain$ ){return 444;}
if ($scheme ~* https) {set $safe 1;}
if ($ssl_server_name !~* ^(.+\.)?first_domain$ ) {set $safe "${safe}0"; }
if ($safe = 10){return 444;}
if ($request_uri ~ "(\"|'|`|~|,|:|--|;|%|\$|&&|\?\?|0x00|0X00|\||\|\{|\}|\[|\]|<|>|\.\.\.|\.\.\/|\/\/\/)"){set $hack 1;}
error_page 400 401 402 403 500 501 502 503 504 =404 /404;
proxy_intercept_errors on;
#Admin Panel
location /admin/ {
proxy_redirect off;
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_pass http://127.0.0.1:35546;
break;
}
location /admin {
proxy_redirect off;
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_pass http://127.0.0.1:35546;
break;
}
#Subscription Path
location /54Z7DF6cq1Ju {
if ($hack = 1) {return 404;}
proxy_redirect off;
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_pass http://127.0.0.1:54272;
break;
}
location /54Z7DF6cq1Ju/ {
if ($hack = 1) {return 404;}
proxy_redirect off;
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_pass http://127.0.0.1:54272;
break;
}
#Subscription Path
location /Qlgbn53Y {
if ($hack = 1) {return 404;}
proxy_redirect off;
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_pass http://127.0.0.1:54272;
break;
}
location /Qlgbn53Y/ {
if ($hack = 1) {return 404;}
proxy_redirect off;
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_pass http://127.0.0.1:54272;
break;
}
#Config Path
location ~ ^/(?<fwdport>\d+)/(?<fwdpath>.*)$ {
if ($hack = 1) {return 404;}
client_max_body_size 0;
client_body_timeout 1d;
grpc_read_timeout 1d;
grpc_socket_keepalive on;
proxy_read_timeout 1d;
proxy_http_version 1.1;
proxy_buffering off;
proxy_request_buffering off;
proxy_socket_keepalive on;
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;
if ($content_type ~* "GRPC") {
grpc_pass grpc://127.0.0.1:$fwdport$is_args$args;
break;
}
if ($http_upgrade ~* "(WEBSOCKET|WS)") {
proxy_pass http://127.0.0.1:$fwdport$is_args$args;
break;
}
if ($request_method ~* ^(PUT|POST|GET)$) {
proxy_pass http://127.0.0.1:$fwdport$is_args$args;
break;
}
}
location / { try_files $uri $uri/ =404; }
}
/etc/nginx/sites-available/second_domain
server {
server_tokens off;
server_name second_domain;
listen 9443 ssl http2;
listen [::]:9443 ssl http2;
index index.html index.htm index.php index.nginx-debian.html;
root /var/www/html/;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!eNULL:!MD5:!DES:!RC4:!ADH:!SSLv3:!EXP:!PSK:!DSS;
ssl_certificate /etc/letsencrypt/live/second_domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/second_domain/privkey.pem;
if ($host !~* ^(.+\.)?second_domain$ ){return 444;}
if ($scheme ~* https) {set $safe 1;}
if ($ssl_server_name !~* ^(.+\.)?second_domain$ ) {set $safe "${safe}0"; }
if ($safe = 10){return 444;}
if ($request_uri ~ "(\"|'|`|~|,|:|--|;|%|\$|&&|\?\?|0x00|0X00|\||\|\{|\}|\[|\]|<|>|\.\.\.|\.\.\/|\/\/\/)"){set $hack 1;}
error_page 400 401 402 403 500 501 502 503 504 =404 /404;
proxy_intercept_errors on;
#Admin Panel
location /admin/ {
proxy_redirect off;
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_pass http://127.0.0.1:35546;
break;
}
location /admin {
proxy_redirect off;
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_pass http://127.0.0.1:35546;
break;
}
#Subscription
location /54Z7DF6cq1Ju {
if ($hack = 1) {return 404;}
proxy_redirect off;
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_pass http://127.0.0.1:54272;
break;
}
location /54Z7DF6cq1Ju/ {
if ($hack = 1) {return 404;}
proxy_redirect off;
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_pass http://127.0.0.1:54272;
break;
}
#Subscription
location /Qlgbn53Y {
if ($hack = 1) {return 404;}
proxy_redirect off;
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_pass http://127.0.0.1:54272;
break;
}
location /Qlgbn53Y/ {
if ($hack = 1) {return 404;}
proxy_redirect off;
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_pass http://127.0.0.1:54272;
break;
}
#Config Path
location ~ ^/(?<fwdport>\d+)/(?<fwdpath>.*)$ {
if ($hack = 1) {return 404;}
client_max_body_size 0;
client_body_timeout 1d;
grpc_read_timeout 1d;
grpc_socket_keepalive on;
proxy_read_timeout 1d;
proxy_http_version 1.1;
proxy_buffering off;
proxy_request_buffering off;
proxy_socket_keepalive on;
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;
if ($content_type ~* "GRPC") {
grpc_pass grpc://127.0.0.1:$fwdport$is_args$args;
break;
}
if ($http_upgrade ~* "(WEBSOCKET|WS)") {
proxy_pass http://127.0.0.1:$fwdport$is_args$args;
break;
}
if ($request_method ~* ^(PUT|POST|GET)$) {
proxy_pass http://127.0.0.1:$fwdport$is_args$args;
break;
}
}
location / { try_files $uri $uri/ =404; }
}
I updated my script to generate the following config files for Traefik:
################################# Traefik Config ########################################################
mkdir -p /etc/traefik/{dynamic,ssl,logs}
cat > /etc/traefik/traefik.yml <<EOF
global:
checkNewVersion: false
sendAnonymousUsage: false
log:
level: INFO
format: json
filePath: /var/log/traefik/traefik.log
accessLog:
filePath: /var/log/traefik/access.log
bufferingSize: 100
format: json
filters:
statusCodes: ["400-499", "500-599"]
entryPoints:
web:
address: :80
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: :443
http:
tls: {}
providers:
docker:
watch: true
exposedByDefault: false
file:
directory: "/etc/traefik/dynamic"
watch: true
ping: {}
metrics:
prometheus: {}
api: {}
certificatesResolvers:
letsencrypt:
acme:
email: email@gmail.com
storage: /etc/traefik/ssl/acme.json
httpChallenge:
entryPoint: web
EOF
cat > /etc/traefik/dynamic/routes.yml <<EOF
http:
routers:
traefik-dashboard:
rule: "Host(\`traefik.first_domain\`)"
entryPoints:
- websecure
service: api@internal
tls:
certResolver: letsencrypt
main-domain:
entryPoints: ["websecure"]
rule: "Host(\`${first_domain}\`)"
service: main-service
middlewares:
- security-headers
- check-host-main
tls:
certResolver: letsencrypt
second-domain:
entryPoints: ["websecure"]
rule: "Host(\`${second_domain}\`)"
service: second-service
middlewares:
- security-headers
- check-host-second
tls:
certResolver: letsencrypt
panel-route:
rule: "Host(\`${domain}\`) || Host(\`${second_domain}\`) && (PathPrefix(\`/${panel_path}\`) || PathPrefix(\`/${panel_path}/\`))"
service: panel-service
entryPoints: ["websecure"]
tls: {}
sub-route:
rule: "Host(\`${domain}\`) || Host(\`${second_domain}\`) && (PathPrefix(\`/${sub_path}\`) || PathPrefix(\`/${sub_path}/\`) || PathPrefix(\`/${json_path}\`) || PathPrefix(\`/${json_path}/\`))"
service: sub-service
entryPoints: ["websecure"]
tls: {}
services:
main-service:
loadBalancer:
servers:
- url: https://127.0.0.1:7443
second-service:
loadBalancer:
servers:
- url: https://127.0.0.1:9443
panel-service:
loadBalancer:
servers:
- url: http://127.0.0.1:${panel_port}
sub-service:
loadBalancer:
servers:
- url: http://127.0.0.1:${sub_port}
middlewares:
security-headers:
headers:
sslRedirect: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
sslForceHost: true
check-host-main:
IPAllowList:
sourceRange:
- 127.0.0.1/32
check-host-second:
IPAllowList:
sourceRange:
- 127.0.0.1/32
tcp:
routers:
sni-router:
rule: "HostSNI(\`${domain}\`) || HostSNI(\`${second_domain}\`)"
service: second-service
tls:
passthrough: true
services:
second-service:
loadBalancer:
servers:
- address: 127.0.0.1:8443
EOF
touch /etc/traefik/ssl/acme.json
chmod 600 /etc/traefik/ssl/acme.json
##################################Install traefik#######################################################
if ! command -v docker &> /dev/null; then
echo "Installing Docker..."
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
echo "Docker installed successfully."
else
echo "Docker already installed."
fi
docker network create frontend
docker network create backend
cat > ./docker-compose.yml <<EOF
networks:
frontend:
external: true
backend:
external: true
services:
traefik:
container_name: traefik
image: traefik:v3.3
networks:
- frontend
- backend
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /etc/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- /etc/traefik/dynamic:/etc/traefik/dynamic
- /etc/traefik/ssl:/etc/traefik/ssl
- /etc/traefik/logs:/var/log/traefik
security_opt:
- no-new-privileges:true
restart: unless-stopped
EOF
echo "Run Traefik in Docker..."
docker compose up -d
generated /etc/traefik/dynamic/routes.yml
http:
routers:
traefik-dashboard:
rule: "Host(`traefik.domain_name`)"
entryPoints:
- websecure
service: api@internal
tls:
certResolver: letsencrypt
main-domain:
entryPoints: ["websecure"]
rule: "Host(`first_domain`)"
service: main-service
middlewares:
- security-headers
- check-host-main
tls:
certResolver: letsencrypt
second-domain:
entryPoints: ["websecure"]
rule: "Host(`second_domain`)"
service: second-service
middlewares:
- security-headers
- check-host-second
tls:
certResolver: letsencrypt
panel-route:
rule: "Host(`first_domain`) || Host(`second_domain`) && (PathPrefix(`/GX5m9Y`) || PathPrefix(`/GX5m9Y/`))"
service: panel-service
entryPoints: ["websecure"]
tls: {}
sub-route:
rule: "Host(`first_domain`) || Host(`second_domain`) && (PathPrefix(`/Qz8Q96ZmPW`) || PathPrefix(`/Qz8Q96ZmPW/`) || PathPrefix(`/ZXzTRjH`) || PathPrefix(`/ZXzTRjH/`))"
service: sub-service
entryPoints: ["websecure"]
tls: {}
services:
main-service:
loadBalancer:
servers:
- url: https://127.0.0.1:7443
second-service:
loadBalancer:
servers:
- url: https://127.0.0.1:9443
panel-service:
loadBalancer:
servers:
- url: http://127.0.0.1:10894
sub-service:
loadBalancer:
servers:
- url: http://127.0.0.1:18005
middlewares:
security-headers:
headers:
sslRedirect: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: "SAMEORIGIN"
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
sslForceHost: true
check-host-main:
IPAllowList:
sourceRange:
- 127.0.0.1/32
check-host-second:
IPAllowList:
sourceRange:
- 127.0.0.1/32
tcp:
routers:
sni-router:
rule: "HostSNI(`first_domain`) || HostSNI(`second_domain`)"
service: second-service
tls:
passthrough: true
services:
second-service:
loadBalancer:
servers:
- address: 127.0.0.1:8443
However, I haven’t been able to get it working. I’m getting "Bad Gateway" errors like this:
{"ClientAddr":"*******","ClientHost":"*********","ClientPort":"******","ClientUsername":"-","DownstreamContentSize":11,"DownstreamStatus":502,"Duration":671292,"OriginContentSize":11,"OriginDuration":405637,"OriginStatus":502,"Overhead":265655,"RequestAddr":"first_domain","RequestContentSize":0,"RequestCount":15,"RequestHost":"first_domain","RequestMethod":"GET","RequestPath":"/","RequestPort":"-","RequestProtocol":"HTTP/2.0","RequestScheme":"https","RetryAttempts":0,"RouterName":"sub-route@file","ServiceAddr":"127.0.0.1:18005","ServiceName":"sub-service@file","ServiceURL":"http://127.0.0.1:18005","SpanId":"0000000000000000","StartLocal":"2025-02-17T14:11:30.923912119Z","StartUTC":"2025-02-17T14:11:30.923912119Z","TLSCipher":"TLS_AES_128_GCM_SHA256","TLSVersion":"1.3","TraceId":"00000000000000000000000000000000","entryPointName":"websecure","level":"info","msg":"","time":"2025-02-17T14:11:30Z"}
ss -tuln | grep 18005
tcp LISTEN 0 4096 *:18005 *:*
Can anyone help me figure out what’s going wrong? Any help would be greatly appreciated!
Thanks in advance!