fix(nginx): prevent cert leak on IPv6 / unknown SNI

Two issues caused TLS to break on photos.carabosse.cloud over IPv6
(GrapheneOS + Immich app via Orange 5G NAT64):

1. Per-service vhosts only listened on IPv4 (listen 443 ssl). On IPv6,
   nginx fell back to the first vhost loaded alphabetically and served
   its certificate, breaking hostname verification on every other vhost.

2. /etc/letsencrypt/{live,archive} were 0700 root:root after certbot
   created them, so the nginx worker (user http on Arch) could not read
   the chained intermediates and served the leaf-only chain.

Changes:
- Add catch-all 00-default.conf default_server on :80 and :443 (v4+v6)
  with a self-signed cert and 'return 444'. ACME challenges still
  answered on :80.
- Add IPv6 listeners ([::]:80 and [::]:443 ssl) to immich, gitea, ntfy,
  uptime_kuma vhosts and to the temporary ACME provisioning vhost.
- Apply 0755 on /etc/letsencrypt/live and /etc/letsencrypt/archive on
  every run, not only at initial cert provisioning.
This commit is contained in:
Clément Désiles
2026-05-30 17:06:10 +02:00
parent 80026fac0b
commit 314fa715fd
10 changed files with 119 additions and 0 deletions
+43
View File
@@ -78,6 +78,49 @@
group: root
mode: "0755"
- name: Configure catch-all default_server
when: nginx_default_server_enabled
block:
- name: Ensure nginx ssl directory exists
ansible.builtin.file:
path: "{{ nginx_default_ssl_cert | dirname }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Generate self-signed cert for default_server
ansible.builtin.command:
cmd: >-
openssl req -x509 -nodes -newkey rsa:2048
-keyout {{ nginx_default_ssl_key }}
-out {{ nginx_default_ssl_cert }}
-days 3650 -subj "/CN=default"
creates: "{{ nginx_default_ssl_cert }}"
- name: Restrict permissions on default_server key
ansible.builtin.file:
path: "{{ nginx_default_ssl_key }}"
owner: root
group: root
mode: "0600"
- name: Deploy default_server vhost
ansible.builtin.template:
src: default-server.conf.j2
dest: "{{ nginx_conf_dir }}/00-default.conf"
owner: root
group: root
mode: "0644"
notify: Reload nginx
- name: Remove default_server vhost when disabled
ansible.builtin.file:
path: "{{ nginx_conf_dir }}/00-default.conf"
state: absent
when: not nginx_default_server_enabled
notify: Reload nginx
- name: Ensure Certbot webroot directory exists
ansible.builtin.file:
path: /var/www/certbot