diff --git a/CHANGELOG.md b/CHANGELOG.md index 92ebd588f9..873142df1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased +- Fix #2393: Make Portainer accessible behind Cloudflare proxy + ## v4.4.16 - 2025-08-15 - 6e04c0b9e - - Fix #2428: AdminUserController should target AdminUserController when validating or rejecting a claim diff --git a/ops/configuration/nginx-conf/sites/nginx.target_deployment.http.conf.dist b/ops/configuration/nginx-conf/sites/nginx.target_deployment.http.conf.dist index 13abc9ad3c..9309ea2426 100644 --- a/ops/configuration/nginx-conf/sites/nginx.target_deployment.http.conf.dist +++ b/ops/configuration/nginx-conf/sites/nginx.target_deployment.http.conf.dist @@ -3,7 +3,27 @@ server { listen 80; listen [::]:80; - server_name $SERVER_HOSTNAME web gigadb.dev gigadb.test; + # Listen on both hostnames that need certificates. + server_name $SERVER_HOSTNAME portainer-$SERVER_HOSTNAME; + + # Handle the challenge requests. + location /.well-known/acme-challenge/ { + root /var/www/.le/; + log_not_found off; + } + + location / { + return 301 https://$host$request_uri; + } + +} + +server { + + listen 80; + listen [::]:80; + + server_name web gigadb.dev gigadb.test; root /var/www; index index.php index.html index.htm; @@ -48,42 +68,5 @@ location /search { deny all; } - location /.well-known/acme-challenge/ { - root /var/www/.le/; - log_not_found off; - } - -} - -server { - - listen 80; - listen [::]:80; - - server_name portainer.$SERVER_HOSTNAME; - root /var/www; - index index.php index.html index.htm; - - location ~* (common\.css|datatables\.css|pager\.css)$ { - expires -1; - } - - location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { - expires 365d; - } - - location / { - try_files $uri $uri/ /index.php$is_args$args; - } - - location ~ /\.ht { - deny all; - } - - location /.well-known/acme-challenge/ { - root /var/www/.le/; - log_not_found off; - } - } diff --git a/ops/configuration/nginx-conf/sites/nginx.target_deployment.https.conf.dist b/ops/configuration/nginx-conf/sites/nginx.target_deployment.https.conf.dist index 92d21bf236..d4db19fd3b 100644 --- a/ops/configuration/nginx-conf/sites/nginx.target_deployment.https.conf.dist +++ b/ops/configuration/nginx-conf/sites/nginx.target_deployment.https.conf.dist @@ -48,7 +48,8 @@ server { fastcgi_send_timeout 600; fastcgi_connect_timeout 600; include fastcgi_params; - include phplimit.conf; + include phplimit.conf; + fastcgi_param HTTPS on; } location /search { @@ -100,6 +101,9 @@ server { listen 443 ssl http2; listen [::]:443 ssl http2; + resolver 127.0.0.11 valid=30s; + + server_name portainer-$SERVER_HOSTNAME; # Security headers add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload"; @@ -114,22 +118,24 @@ server { add_header Access-Control-Allow-Methods '*'; add_header Access-Control-Allow-Headers '*'; - - server_name portainer.$SERVER_HOSTNAME; - root /var/www; - index index.php index.html index.htm; - location / { proxy_http_version 1.1; proxy_set_header Connection ""; - proxy_pass http://portainer:9000; + + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto https; + + set $upstream_portainer http://portainer:9000; + proxy_pass $upstream_portainer; } location /api/websocket/ { proxy_http_version 1.1; proxy_set_header Connection "upgrade"; proxy_set_header Upgrade $http_upgrade; - proxy_pass http://portainer:9000/api/websocket; + + set $upstream_portainer_ws http://portainer:9000/api/websocket; + proxy_pass $upstream_portainer_ws; } location ~ /\.ht { @@ -148,12 +154,9 @@ server { ssl_dhparam /etc/ssl/nginx/dhparam.pem; # intermediate configuration. tweak to your needs. - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; - ssl_prefer_server_ciphers on; - - # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) - add_header Strict-Transport-Security max-age=15768000; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; # OCSP Stapling --- # fetch OCSP records from URL in ssl_certificate and cache them diff --git a/ops/deployment/docker-compose.production-envs.yml b/ops/deployment/docker-compose.production-envs.yml index 7a04660564..2996031d0d 100644 --- a/ops/deployment/docker-compose.production-envs.yml +++ b/ops/deployment/docker-compose.production-envs.yml @@ -302,6 +302,8 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock - portainer_data:/data + environment: + - TRUSTED_ORIGINS=portainer-$REMOTE_HOSTNAME ports: - 9009:9000 - 8000:8000 diff --git a/ops/scripts/setup_cert.sh b/ops/scripts/setup_cert.sh index 3d70b16d6b..008c4cf7a4 100755 --- a/ops/scripts/setup_cert.sh +++ b/ops/scripts/setup_cert.sh @@ -90,7 +90,7 @@ fetch_cert_from_gitlab() { make_new_cert() { echo "Running certbot to make new cert" - $DOCKER_COMPOSE run --rm certbot certonly -d $REMOTE_HOSTNAME -d portainer.$REMOTE_HOSTNAME + $DOCKER_COMPOSE run --rm certbot certonly -d $REMOTE_HOSTNAME -d portainer-$REMOTE_HOSTNAME echo "Read content of files" $DOCKER_COMPOSE run --rm config mkdir -vp /etc/letsencrypt/archive/$REMOTE_HOSTNAME $DOCKER_COMPOSE run --rm config mkdir -vp /etc/letsencrypt/live/$REMOTE_HOSTNAME