From 1714f3610ab1aee3f163cd0c8bcd4c6ab9a39105 Mon Sep 17 00:00:00 2001 From: Ryan Aslett Date: Fri, 25 Sep 2026 09:55:51 -0700 Subject: [PATCH 1/2] ansible: capture jenkins-nginx config for ci and ci-release Adds a jenkins-nginx role that reproduces the nginx reverse proxy already running by hand in front of the Jenkins masters on ci.nodejs.org and ci-release.nodejs.org: package install, dhparam, proxy_cache_path config, per-host site config, and (ci.nodejs.org only) the /server_status stub_status page. Templates and files were captured from the live hosts and verified byte-for-byte against the running config (aside from one straight- quote fix to an already mismatched-quote typo in the ci.nodejs.org comment). This is a management-only change: no nginx behavior changes on either host. This is the first PR in a stack leading up to automating certbot for these hosts. Co-Authored-By: Claude Sonnet 5 Signed-off-by: Ryan Aslett --- ansible/playbooks/jenkins/host/create.yml | 9 ++ ansible/roles/jenkins-nginx/files/dhparam.pem | 13 ++ .../jenkins-nginx/files/jenkins-static.conf | 1 + ansible/roles/jenkins-nginx/files/status.conf | 11 ++ ansible/roles/jenkins-nginx/tasks/main.yml | 56 +++++++++ .../templates/ci-release.nodejs.org.conf.j2 | 80 +++++++++++++ .../templates/ci.nodejs.org.conf.j2 | 111 ++++++++++++++++++ 7 files changed, 281 insertions(+) create mode 100644 ansible/roles/jenkins-nginx/files/dhparam.pem create mode 100644 ansible/roles/jenkins-nginx/files/jenkins-static.conf create mode 100644 ansible/roles/jenkins-nginx/files/status.conf create mode 100644 ansible/roles/jenkins-nginx/tasks/main.yml create mode 100644 ansible/roles/jenkins-nginx/templates/ci-release.nodejs.org.conf.j2 create mode 100644 ansible/roles/jenkins-nginx/templates/ci.nodejs.org.conf.j2 diff --git a/ansible/playbooks/jenkins/host/create.yml b/ansible/playbooks/jenkins/host/create.yml index 4fbed1510..222ef9253 100644 --- a/ansible/playbooks/jenkins/host/create.yml +++ b/ansible/playbooks/jenkins/host/create.yml @@ -10,7 +10,16 @@ roles: - bootstrap + - package-upgrade - baselayout tasks: # - name: place init script + +- hosts: infra-digitalocean-ubuntu2204-x64-1 # ci.nodejs.org + roles: + - { role: jenkins-nginx, jenkins_nginx_fqdn: 'ci.nodejs.org', jenkins_nginx_status_page: true } + +- hosts: infra-ibm-ubuntu2404-x64-1 # ci-release.nodejs.org + roles: + - { role: jenkins-nginx, jenkins_nginx_fqdn: 'ci-release.nodejs.org' } diff --git a/ansible/roles/jenkins-nginx/files/dhparam.pem b/ansible/roles/jenkins-nginx/files/dhparam.pem new file mode 100644 index 000000000..6acdf701d --- /dev/null +++ b/ansible/roles/jenkins-nginx/files/dhparam.pem @@ -0,0 +1,13 @@ +-----BEGIN DH PARAMETERS----- +MIICCAKCAgEApD4ksbd6LDk6C+qy/9n9dtMEeoEN07TMpgfTRgQxaHR5XVLD5/89 ++mQyOFzSwxVXSWEg+bVSOsL1DDZg9DrvNNe+2yOI5eIYNTH0bWGoK0H/BsaPeHXf +UoNWp785VT2afImKPTVs7cwNiIFUNKh4bOYjEWKswM7eSWgEqYF2QqZOeJIbDuXg +9tiEp0fe4U8Qhyg9GsCBd9LfQRdaoiOiWFuMx66IrBKLWAYV2fBj1M9Q6+ofXOnS +xKgRWMK6tm5Va72lmrXxr4poFIdzv3VUjczOXwchh4IRgWj50zrYVxiaMMX5OJre +SBeNgRZ0I4cLu1JdboFDFjMPpqOvG58cY5+rLLc+ffBnc+ybXVL+BxiA9KGxu2mY +3Bscgd7slU2TXaHtiP7+MEnxQsO6JYrUrPpuuC14IzHmCH1mmd5oOy0iJQJesP4c +SH+0V0flLtI8RcSZIMTlYqXegMBgVIS8p8fOzL8IGgeHXwe5DIEMv0VYtyB1J2sl +cEjEZW+wOsDvJh4qk9i05VtQOg4f1PCaelLc+fE3zf+vGTCvX09JBFrX/m/VQ/2c +3EdGRNBa6aGyGXdagd1mAp6abwCcb87ciL35Ho68blgIMLZWsjX0FeJT/hHOjNQu +1egu4mrSkZMQ5Nq9ExH/EfaQKkzCozd5rUf+AJESfoEJH40WMjTmZ3sCAQI= +-----END DH PARAMETERS----- diff --git a/ansible/roles/jenkins-nginx/files/jenkins-static.conf b/ansible/roles/jenkins-nginx/files/jenkins-static.conf new file mode 100644 index 000000000..170fde097 --- /dev/null +++ b/ansible/roles/jenkins-nginx/files/jenkins-static.conf @@ -0,0 +1 @@ +proxy_cache_path /var/lib/nginx/jenkins-cache levels=1:2 keys_zone=jenkins-static:10m inactive=24h max_size=5g; diff --git a/ansible/roles/jenkins-nginx/files/status.conf b/ansible/roles/jenkins-nginx/files/status.conf new file mode 100644 index 000000000..f1b9135d6 --- /dev/null +++ b/ansible/roles/jenkins-nginx/files/status.conf @@ -0,0 +1,11 @@ +server { + + listen localhost:80; + location /server_status { + stub_status on; + + access_log off; + allow 127.0.0.1; + deny all; + } +} diff --git a/ansible/roles/jenkins-nginx/tasks/main.yml b/ansible/roles/jenkins-nginx/tasks/main.yml new file mode 100644 index 000000000..ff3315f5a --- /dev/null +++ b/ansible/roles/jenkins-nginx/tasks/main.yml @@ -0,0 +1,56 @@ +--- + +# +# installs and configures the nginx reverse proxy that fronts a Jenkins +# master, matching the config already running by hand on ci.nodejs.org +# and ci-release.nodejs.org. +# +# expects: +# jenkins_nginx_fqdn: the hostname this proxy serves (e.g. ci.nodejs.org). +# Selects the site template `{{ jenkins_nginx_fqdn }}.conf.j2`. +# jenkins_nginx_status_page: whether to install the localhost-only +# `/server_status` stub_status site (only ci.nodejs.org has this today). +# Defaults to false. +# + +- name: jenkins-nginx | install nginx + package: + name: nginx + state: present + +- name: jenkins-nginx | ensure conf.d cache path config + copy: + src: jenkins-static.conf + dest: /etc/nginx/conf.d/jenkins-static.conf + mode: 0644 + +- name: jenkins-nginx | ensure dhparam + copy: + src: dhparam.pem + dest: /etc/nginx/ssl/dhparam.pem + mode: 0644 + +- name: jenkins-nginx | copy site config to sites-available + template: + src: "{{ jenkins_nginx_fqdn }}.conf.j2" + dest: /etc/nginx/sites-available/jenkins-iojs + mode: 0644 + +- name: jenkins-nginx | symlink site into sites-enabled + file: + src: /etc/nginx/sites-available/jenkins-iojs + dest: /etc/nginx/sites-enabled/jenkins-iojs + state: link + +- name: jenkins-nginx | install status page + copy: + src: status.conf + dest: /etc/nginx/sites-enabled/status.conf + mode: 0644 + when: jenkins_nginx_status_page | default(false) + +- name: jenkins-nginx | enable and start nginx + service: + name: nginx + state: started + enabled: yes diff --git a/ansible/roles/jenkins-nginx/templates/ci-release.nodejs.org.conf.j2 b/ansible/roles/jenkins-nginx/templates/ci-release.nodejs.org.conf.j2 new file mode 100644 index 000000000..32d4a2e3e --- /dev/null +++ b/ansible/roles/jenkins-nginx/templates/ci-release.nodejs.org.conf.j2 @@ -0,0 +1,80 @@ +server { + listen 80; + server_name {{ jenkins_nginx_fqdn }}; + return 301 https://{{ jenkins_nginx_fqdn }}$request_uri; +} + +server { + listen 443 default_server ssl http2; + server_name {{ jenkins_nginx_fqdn }}; + + ssl_certificate ssl/nodejs_chained.crt; + ssl_certificate_key ssl/nodejs.key; + + ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"; + ssl_prefer_server_ciphers on; + ssl_dhparam ssl/dhparam.pem; + ssl_session_timeout 5m; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_session_cache shared:SSL:50m; + + ssl_stapling on; + ssl_stapling_verify on; + ssl_trusted_certificate ssl/nodejs_chained.crt; + resolver 8.8.4.4 8.8.8.8 valid=300s; + resolver_timeout 10s; + + add_header Strict-Transport-Security max-age=15552000; + + access_log /var/log/nginx/jenkins-iojs-access.log; + error_log /var/log/nginx/jenkins-iojs-error.log; + + gzip on; + gzip_static on; + gzip_disable "MSIE [1-6]\."; + default_type text/html; + gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; + + location /static/ { + 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; + + proxy_cache jenkins-static; + proxy_cache_valid 200 1y; + proxy_cache_use_stale error timeout invalid_header updating + http_500 http_502 http_503 http_504; + + expires 1y; + + proxy_pass http://localhost:8080; + proxy_read_timeout 90; + } + + location / { + + 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; + + proxy_pass http://localhost:8080; + proxy_read_timeout 90; + + # Hide jenkins headers because reasons + proxy_hide_header X-Hudson-CLI-Port; + proxy_hide_header X-Jenkins-CLI-Port; + proxy_hide_header X-Jenkins-CLI2-Port; + + proxy_redirect http://localhost:8080 https://{{ jenkins_nginx_fqdn }}; + } + + location ~ ^/cli { + return 403; + } + + location /theme/ { + alias /var/lib/jenkins/theme/; + } +} diff --git a/ansible/roles/jenkins-nginx/templates/ci.nodejs.org.conf.j2 b/ansible/roles/jenkins-nginx/templates/ci.nodejs.org.conf.j2 new file mode 100644 index 000000000..79313406a --- /dev/null +++ b/ansible/roles/jenkins-nginx/templates/ci.nodejs.org.conf.j2 @@ -0,0 +1,111 @@ +server { + listen *:80; + listen [::]:80 ipv6only=on; + server_name {{ jenkins_nginx_fqdn }}; + + keepalive_timeout 60; + server_tokens off; + + resolver 8.8.4.4 8.8.8.8 valid=300s; + resolver_timeout 10s; + + access_log /var/log/nginx/jenkins-iojs-access.log; + error_log /var/log/nginx/jenkins-iojs-error.log; + + gzip on; + gzip_static on; + gzip_disable "MSIE [1-6]\."; + default_type text/html; + gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; + + location /downloads/ { + alias /home/downloads/www/; + autoindex on; + } + + location / { + rewrite ^ https://{{ jenkins_nginx_fqdn }}$request_uri permanent; + } + + index index.html; +} + +server { + listen 443 default_server ssl spdy; + server_name {{ jenkins_nginx_fqdn }}; + + ssl_certificate ssl/nodejs_chained.crt; + ssl_certificate_key ssl/nodejs.key; + + ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"; + ssl_prefer_server_ciphers on; + ssl_dhparam ssl/dhparam.pem; + ssl_session_timeout 5m; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_session_cache shared:SSL:50m; + + ssl_stapling on; + ssl_stapling_verify on; + ssl_trusted_certificate ssl/nodejs_chained.crt; + resolver 8.8.4.4 8.8.8.8 valid=300s; + resolver_timeout 10s; + + access_log /var/log/nginx/jenkins-iojs-access.log; + error_log /var/log/nginx/jenkins-iojs-error.log; + + gzip on; + gzip_static on; + gzip_disable "MSIE [1-6]\."; + default_type text/html; + gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; + + location /downloads/ { + alias /home/downloads/www/; + autoindex on; + } + + location /static/ { + 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; + + proxy_cache jenkins-static; + proxy_cache_valid 200 1y; + proxy_cache_use_stale error timeout invalid_header updating + http_500 http_502 http_503 http_504; + + expires 1y; + + proxy_pass http://localhost:8080; + proxy_read_timeout 240; + } + + location /theme/ { + alias /var/lib/jenkins/theme/; + expires max; + } + + location ~ ^/cli { + return 403; + } + + location / { + + 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; + + # Fix the "It appears that your reverse proxy set up is broken" error. + proxy_pass http://localhost:8080; + proxy_read_timeout 90; + + # Hide jenkins headers because reasons + proxy_hide_header X-Hudson-CLI-Port; + proxy_hide_header X-Jenkins-CLI-Port; + proxy_hide_header X-Jenkins-CLI2-Port; + + proxy_redirect http://localhost:8080 https://{{ jenkins_nginx_fqdn }}; + } +} From d5ba4ed5daa1c1000ed411fc7ae05eb27165d634 Mon Sep 17 00:00:00 2001 From: Ryan Aslett Date: Fri, 25 Sep 2026 14:04:26 -0700 Subject: [PATCH 2/2] Create SSL directory for Nginx Ensure the SSL directory for Nginx exists with proper permissions. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- ansible/roles/jenkins-nginx/tasks/main.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ansible/roles/jenkins-nginx/tasks/main.yml b/ansible/roles/jenkins-nginx/tasks/main.yml index ff3315f5a..f65840101 100644 --- a/ansible/roles/jenkins-nginx/tasks/main.yml +++ b/ansible/roles/jenkins-nginx/tasks/main.yml @@ -24,6 +24,12 @@ dest: /etc/nginx/conf.d/jenkins-static.conf mode: 0644 +- name: jenkins-nginx | ensure nginx ssl directory + file: + path: /etc/nginx/ssl + state: directory + mode: 0755 + - name: jenkins-nginx | ensure dhparam copy: src: dhparam.pem