From 8250508b8018c8eb72c7f42ad23e6663826e28fe Mon Sep 17 00:00:00 2001 From: Bianca Nenciu Date: Thu, 19 Sep 2024 20:01:14 +0300 Subject: [PATCH] Add nginx config file and support for outlets The nginx config file used to be copied from the discourse/discourse repository, but it has been now moved in this project, closer to the place where it is used. The config has several 'include' statements that implement support for outlets that templates can then use to extend the default configuration for various features. This is an alternative to the "find & replace" hacks. --- samples/standalone.yml | 2 - samples/web_only.yml | 2 - templates/offline-page.template.yml | 19 ++-- templates/sshd.template.yml | 4 + templates/web.ipv6.template.yml | 12 +-- templates/web.letsencrypt.ssl.template.yml | 22 ++--- templates/web.ratelimited.template.yml | 17 ++-- templates/web.socketed.template.yml | 10 +- templates/web.ssl.template.yml | 105 ++++++++++----------- templates/web.template.yml | 27 +++--- 10 files changed, 97 insertions(+), 123 deletions(-) diff --git a/samples/standalone.yml b/samples/standalone.yml index e6d946f03..a4c3bd5d6 100644 --- a/samples/standalone.yml +++ b/samples/standalone.yml @@ -11,8 +11,6 @@ templates: - "templates/postgres.template.yml" - "templates/redis.template.yml" - "templates/web.template.yml" - ## Uncomment the next line to enable the IPv6 listener - #- "templates/web.ipv6.template.yml" - "templates/web.ratelimited.template.yml" ## Uncomment these two lines if you wish to add Lets Encrypt (https) #- "templates/web.ssl.template.yml" diff --git a/samples/web_only.yml b/samples/web_only.yml index c4753dde0..d335c847e 100644 --- a/samples/web_only.yml +++ b/samples/web_only.yml @@ -3,8 +3,6 @@ templates: - "templates/web.template.yml" - ## Uncomment the next line to enable the IPv6 listener - #- "templates/web.ipv6.template.yml" - "templates/web.ratelimited.template.yml" ## Uncomment these two lines if you wish to add Lets Encrypt (https) #- "templates/web.ssl.template.yml" diff --git a/templates/offline-page.template.yml b/templates/offline-page.template.yml index 9bcd7723f..6741f07be 100644 --- a/templates/offline-page.template.yml +++ b/templates/offline-page.template.yml @@ -7,17 +7,14 @@ params: offline_page_repository: https://github.com/discourse/discourse-offline-page.git run: - - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - global: true - from: /server.+{/ - to: | - server { - error_page 502 /error_page.html; - location /error_page.html { - root /var/www/discourse-offline-page/html; - internal; - } + - file: + path: "/etc/nginx/conf.d/outlets/server/offline-page.conf" + contents: | + error_page 502 /error_page.html; + location /error_page.html { + root /var/www/discourse-offline-page/html; + internal; + } - exec: cmd: git clone $offline_page_repository /var/www/discourse-offline-page diff --git a/templates/sshd.template.yml b/templates/sshd.template.yml index d9bf57c2a..b8f3f1587 100644 --- a/templates/sshd.template.yml +++ b/templates/sshd.template.yml @@ -1,2 +1,6 @@ # This file is deprecated; you can remove it from your app.yml +# TODO(2026-01-01): Remove this file run: + - exec: |- + echo "Deprecation warning: sshd is no longer supported" + echo "Remove templates/sshd.template.yml from your containers/*.yml files" diff --git a/templates/web.ipv6.template.yml b/templates/web.ipv6.template.yml index bf589fe24..c429fc31c 100644 --- a/templates/web.ipv6.template.yml +++ b/templates/web.ipv6.template.yml @@ -1,8 +1,6 @@ +# This file is deprecated; you can remove it from your app.yml +# TODO(2026-01-01): Remove this file run: - - exec: echo "Enabling IPv6 listener" - - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: listen 80; - to: | - listen 80; - listen [::]:80; + - exec: |- + echo "Deprecation warning: IPv6 is enabled by default when possible" + echo "Remove templates/web.ipv6.template.yml from your containers/*.yml files" diff --git a/templates/web.letsencrypt.ssl.template.yml b/templates/web.letsencrypt.ssl.template.yml index ba5f55178..ff96657e8 100644 --- a/templates/web.letsencrypt.ssl.template.yml +++ b/templates/web.letsencrypt.ssl.template.yml @@ -106,13 +106,6 @@ hooks: /usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop - - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /ssl_certificate.+/ - to: | - ssl_certificate /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.cer; - ssl_certificate /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.cer; - - replace: filename: /shared/letsencrypt/account.conf from: /#?ACCOUNT_EMAIL=.+/ @@ -120,14 +113,15 @@ hooks: ACCOUNT_EMAIL=$$ENV_LETSENCRYPT_ACCOUNT_EMAIL - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /ssl_certificate_key.+/ + filename: "/etc/nginx/conf.d/outlets/server/https.conf" + from: /ssl_certificate.+/ to: | - ssl_certificate_key /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.key; - ssl_certificate_key /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.key; + ssl_certificate /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.cer; + ssl_certificate /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.cer; - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /add_header.+/ + filename: "/etc/nginx/conf.d/outlets/server/https.conf" + from: /ssl_certificate_key.+/ to: | - add_header Strict-Transport-Security 'max-age=63072000'; + ssl_certificate_key /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.key; + ssl_certificate_key /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.key; diff --git a/templates/web.ratelimited.template.yml b/templates/web.ratelimited.template.yml index ae9cd636c..ca4cd4b2c 100644 --- a/templates/web.ratelimited.template.yml +++ b/templates/web.ratelimited.template.yml @@ -6,21 +6,18 @@ params: conn_per_ip: 20 run: - - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /server.+{/ - to: | + - file: + path: "/etc/nginx/conf.d/outlets/before-server/ratelimited.conf" + contents: | limit_req_zone $binary_remote_addr zone=flood:10m rate=$reqs_per_secondr/s; limit_req_zone $binary_remote_addr zone=bot:10m rate=$reqs_per_minuter/m; limit_req_status 429; limit_conn_zone $binary_remote_addr zone=connperip:10m; limit_conn_status 429; - server { - - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: "/location @discourse {/" - to: | - location @discourse { + + - file: + path: "/etc/nginx/conf.d/outlets/discourse/ratelimited.conf" + contents: | limit_conn connperip $conn_per_ip; limit_req zone=flood burst=$burst_per_second nodelay; limit_req zone=bot burst=$burst_per_minute nodelay; diff --git a/templates/web.socketed.template.yml b/templates/web.socketed.template.yml index ff4f87a1b..28787814d 100644 --- a/templates/web.socketed.template.yml +++ b/templates/web.socketed.template.yml @@ -12,14 +12,14 @@ run: #!/bin/bash rm -rf /shared/nginx.http*.sock - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /listen 80;/ + filename: "/etc/nginx/conf.d/outlets/server/http.conf" + from: /listen 80;(\nlisten \[::\]:80;)?/ to: | listen unix:/shared/nginx.http.sock; set_real_ip_from unix:; - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /listen 443 ssl http2;/ + filename: "/etc/nginx/conf.d/outlets/server/https.conf" + from: /listen 443 ssl;(\nlisten \[::\]:443 ssl;)?/ to: | - listen unix:/shared/nginx.https.sock ssl http2; + listen unix:/shared/nginx.https.sock ssl; set_real_ip_from unix:; diff --git a/templates/web.ssl.template.yml b/templates/web.ssl.template.yml index cc6a66fe0..9a3fc0b44 100644 --- a/templates/web.ssl.template.yml +++ b/templates/web.ssl.template.yml @@ -1,58 +1,51 @@ run: - exec: - cmd: - - "mkdir -p /shared/ssl/" - - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /server.+{/ - to: | - server { - listen 80; - return 301 https://$$ENV_DISCOURSE_HOSTNAME$request_uri; - } - server { - - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /listen 80;\s+gzip on;/m - to: | - listen 443 ssl; - http2 on; - SSL_TEMPLATE_SSL_BLOCK - - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /listen 80;\s+listen \[::\]:80;\s+gzip on;/m - to: | - listen 443 ssl; - listen [::]:443 ssl; - http2 on; - SSL_TEMPLATE_SSL_BLOCK - - replace: - hook: ssl - filename: "/etc/nginx/conf.d/discourse.conf" - from: /SSL_TEMPLATE_SSL_BLOCK/ - to: | - - 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; - - ssl_certificate /shared/ssl/ssl.crt; - ssl_certificate_key /shared/ssl/ssl.key; - - ssl_session_tickets off; - ssl_session_timeout 1d; - ssl_session_cache shared:SSL:1m; - - gzip on; - - add_header Strict-Transport-Security 'max-age=31536000'; # remember the certificate for a year and automatically connect to HTTPS for this domain - - if ($http_host != $$ENV_DISCOURSE_HOSTNAME) { - rewrite (.*) https://$$ENV_DISCOURSE_HOSTNAME$1 permanent; - } - - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: "location @discourse {" - to: | - location @discourse { - add_header Strict-Transport-Security 'max-age=31536000'; # remember the certificate for a year and automatically connect to HTTPS for this domain + cmd: + - "mkdir -p /shared/ssl/" + + - file: + path: "/etc/nginx/conf.d/outlets/before-server/redirect-http-to-https.conf" + contents: | + server { + listen 80; + return 301 https://$$ENV_DISCOURSE_HOSTNAME$request_uri; + } + + - exec: rm /etc/nginx/conf.d/outlets/server/http.conf + + - file: + hook: ssl + path: "/etc/nginx/conf.d/outlets/server/https.conf" + contents: | + listen 443 ssl; + http2 on; + + 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; + + ssl_certificate /shared/ssl/ssl.crt; + ssl_certificate_key /shared/ssl/ssl.key; + + ssl_session_tickets off; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:1m; + + add_header Strict-Transport-Security 'max-age=31536000'; + + if ($http_host != $$ENV_DISCOURSE_HOSTNAME) { + rewrite (.*) https://$$ENV_DISCOURSE_HOSTNAME$1 permanent; + } + + - file: + path: "/etc/nginx/conf.d/outlets/discourse/https.conf" + contents: | + add_header Strict-Transport-Security 'max-age=31536000'; + + - exec: + cmd: + - |- + if [ -f "/proc/net/if_inet6" ] ; then + sed -i 's/listen 80;/listen 80;\nlisten [::]:80;/g' /etc/nginx/conf.d/outlets/before-server/redirect-http-to-https.conf + sed -i 's/listen 443 ssl;/listen 443 ssl;\nlisten [::]:443 ssl;/g' /etc/nginx/conf.d/outlets/server/https.conf + fi diff --git a/templates/web.template.yml b/templates/web.template.yml index 9b541c9c2..f0bf06a0b 100644 --- a/templates/web.template.yml +++ b/templates/web.template.yml @@ -132,7 +132,6 @@ run: - exec: cmd: - - "cp $home/config/nginx.sample.conf /etc/nginx/conf.d/discourse.conf" - "rm /etc/nginx/sites-enabled/default" - "mkdir -p /var/nginx/cache" @@ -142,26 +141,21 @@ run: to: daemon off; - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /upstream[^\}]+\}/m - to: "upstream discourse { - server 127.0.0.1:3000; - }" - - - replace: - filename: "/etc/nginx/conf.d/discourse.conf" - from: /server_name.+$/ - to: server_name _ ; + filename: "/etc/nginx/nginx.conf" + from: /worker_connections.+$/ + to: worker_connections $nginx_worker_connections; - replace: filename: "/etc/nginx/conf.d/discourse.conf" from: /client_max_body_size.+$/ - to: client_max_body_size $upload_size ; + to: client_max_body_size $upload_size; - - replace: - filename: "/etc/nginx/nginx.conf" - from: /worker_connections.+$/ - to: worker_connections $nginx_worker_connections ; + - exec: + cmd: + - |- + if [ -f "/proc/net/if_inet6" ]; then + sed -i 's/listen 80;/listen 80;\nlisten [::]:80;/g' /etc/nginx/conf.d/outlets/server/http.conf + fi - exec: cmd: echo "done configuring web" @@ -222,6 +216,7 @@ run: hook: assets_precompile cmd: - su discourse -c 'SKIP_EMBER_CLI_COMPILE=1 bundle exec rake themes:update assets:precompile' + - replace: tag: precompile filename: /etc/service/unicorn/run