From 0a9185ff3eef56588e7624a539039bb5720fc4e9 Mon Sep 17 00:00:00 2001 From: Ruben Hensen Date: Sun, 15 Mar 2026 13:15:16 +0100 Subject: [PATCH] Point rubenhensen.nl to mailserver for reverse proxy --- .../mailserver/host_vars/mailserver/vars.yml | 1 + .../mailserver/roles/nginx/defaults/main.yml | 5 ++ ansible/mailserver/roles/nginx/tasks/main.yml | 88 +++++++++++++++++++ .../nginx/templates/k8s-backend-ip.conf.j2 | 1 + .../roles/nginx/templates/k8s-proxy.conf.j2 | 17 ++++ .../nginx/templates/k8s-upstream.conf.j2 | 3 + .../roles/nginx/templates/mail.conf.j2 | 6 +- .../roles/nginx/templates/nginx.conf.j2 | 54 ++++++++++++ dns/domains/rubenhensen.nl.yaml | 2 +- ip-updater/cronjob.yaml | 2 - 10 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 ansible/mailserver/roles/nginx/templates/k8s-backend-ip.conf.j2 create mode 100644 ansible/mailserver/roles/nginx/templates/k8s-proxy.conf.j2 create mode 100644 ansible/mailserver/roles/nginx/templates/k8s-upstream.conf.j2 create mode 100644 ansible/mailserver/roles/nginx/templates/nginx.conf.j2 diff --git a/ansible/mailserver/host_vars/mailserver/vars.yml b/ansible/mailserver/host_vars/mailserver/vars.yml index 0eea35c..f95638a 100644 --- a/ansible/mailserver/host_vars/mailserver/vars.yml +++ b/ansible/mailserver/host_vars/mailserver/vars.yml @@ -2,3 +2,4 @@ stalwart_fallback_admin_password: "{{ vault_stalwart_fallback_admin_password }}" stalwart_db_password: "{{ vault_stalwart_db_password }}" sogo_db_password: "{{ vault_sogo_db_password }}" +nginx_k8s_updater_ssh_pubkey: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII5cMc73rlUCn3mS5FXlu3nO+AUeW2L28jRh22VYIPY4 k8s-ip-updater" diff --git a/ansible/mailserver/roles/nginx/defaults/main.yml b/ansible/mailserver/roles/nginx/defaults/main.yml index a413154..ac673e2 100644 --- a/ansible/mailserver/roles/nginx/defaults/main.yml +++ b/ansible/mailserver/roles/nginx/defaults/main.yml @@ -5,3 +5,8 @@ nginx_tls_cert: "/etc/letsencrypt/live/mail.rubenhensen.nl/fullchain.pem" nginx_tls_key: "/etc/letsencrypt/live/mail.rubenhensen.nl/privkey.pem" nginx_stalwart_backend: "127.0.0.1:8443" nginx_sogo_backend: "127.0.0.1:20000" + +nginx_local_tls_domains: + - mail.rubenhensen.nl + - stalwart.rubenhensen.nl +nginx_k8s_upstream_conf: "/etc/nginx/stream.d/k8s-upstream.conf" diff --git a/ansible/mailserver/roles/nginx/tasks/main.yml b/ansible/mailserver/roles/nginx/tasks/main.yml index e6515eb..335ed54 100644 --- a/ansible/mailserver/roles/nginx/tasks/main.yml +++ b/ansible/mailserver/roles/nginx/tasks/main.yml @@ -4,6 +4,24 @@ name: nginx state: present +- name: Install nginx stream modules + ansible.builtin.apt: + name: libnginx-mod-stream + state: present + +- name: Create stream.d directory + ansible.builtin.file: + path: /etc/nginx/stream.d + state: directory + mode: "0755" + +- name: Deploy nginx.conf + ansible.builtin.template: + src: nginx.conf.j2 + dest: /etc/nginx/nginx.conf + mode: "0644" + notify: reload nginx + - name: Remove default site ansible.builtin.file: path: /etc/nginx/sites-enabled/default @@ -24,6 +42,76 @@ state: link notify: reload nginx +- name: Deploy K8s upstream config (initial only) + ansible.builtin.template: + src: k8s-upstream.conf.j2 + dest: "{{ nginx_k8s_upstream_conf }}" + mode: "0644" + force: false + notify: reload nginx + +- name: Deploy K8s backend IP config (initial only) + ansible.builtin.template: + src: k8s-backend-ip.conf.j2 + dest: /etc/nginx/k8s-backend-ip.conf + mode: "0644" + force: false + notify: reload nginx + +- name: Deploy K8s HTTP proxy config + ansible.builtin.template: + src: k8s-proxy.conf.j2 + dest: /etc/nginx/sites-available/k8s-proxy.conf + mode: "0644" + notify: reload nginx + +- name: Enable K8s proxy site + ansible.builtin.file: + src: /etc/nginx/sites-available/k8s-proxy.conf + dest: /etc/nginx/sites-enabled/k8s-proxy.conf + state: link + notify: reload nginx + +- name: Deploy K8s IP update script + ansible.builtin.copy: + dest: /usr/local/bin/update-k8s-ip + content: | + #!/bin/bash + NEW_IP="$SSH_ORIGINAL_COMMAND" + + if ! echo "$NEW_IP" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "Invalid IP: $NEW_IP" + exit 1 + fi + + CONF="{{ nginx_k8s_upstream_conf }}" + CURRENT_IP=$(grep -oP 'server \K[0-9.]+' "$CONF" 2>/dev/null) + + if [ "$CURRENT_IP" = "$NEW_IP" ]; then + echo "IP unchanged: $NEW_IP" + exit 0 + fi + + printf 'upstream k8s_tls {\n server %s:443;\n}\n' "$NEW_IP" > "$CONF" + printf 'set $k8s_ip %s;\n' "$NEW_IP" > /etc/nginx/k8s-backend-ip.conf + + nginx -t && systemctl reload nginx + echo "Updated K8s backend IP to $NEW_IP" + mode: "0755" + +- name: Ensure .ssh directory exists for root + ansible.builtin.file: + path: /root/.ssh + state: directory + mode: "0700" + +- name: Deploy SSH authorized key for K8s IP updater + ansible.builtin.authorized_key: + user: root + key: "{{ nginx_k8s_updater_ssh_pubkey }}" + key_options: 'command="/usr/local/bin/update-k8s-ip",no-port-forwarding,no-X11-forwarding,no-agent-forwarding' + when: nginx_k8s_updater_ssh_pubkey is defined + - name: Enable and start Nginx ansible.builtin.systemd: name: nginx diff --git a/ansible/mailserver/roles/nginx/templates/k8s-backend-ip.conf.j2 b/ansible/mailserver/roles/nginx/templates/k8s-backend-ip.conf.j2 new file mode 100644 index 0000000..457eda0 --- /dev/null +++ b/ansible/mailserver/roles/nginx/templates/k8s-backend-ip.conf.j2 @@ -0,0 +1 @@ +set $k8s_ip 127.0.0.1; diff --git a/ansible/mailserver/roles/nginx/templates/k8s-proxy.conf.j2 b/ansible/mailserver/roles/nginx/templates/k8s-proxy.conf.j2 new file mode 100644 index 0000000..b2474b0 --- /dev/null +++ b/ansible/mailserver/roles/nginx/templates/k8s-proxy.conf.j2 @@ -0,0 +1,17 @@ +# Catch-all for any domain not handled by mail.conf +# Proxies ACME challenges to K8s for cert-manager, redirects rest to HTTPS +server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + + location /.well-known/acme-challenge/ { + include /etc/nginx/k8s-backend-ip.conf; + proxy_pass http://$k8s_ip:80; + proxy_set_header Host $host; + } + + location / { + return 301 https://$host$request_uri; + } +} diff --git a/ansible/mailserver/roles/nginx/templates/k8s-upstream.conf.j2 b/ansible/mailserver/roles/nginx/templates/k8s-upstream.conf.j2 new file mode 100644 index 0000000..71c3324 --- /dev/null +++ b/ansible/mailserver/roles/nginx/templates/k8s-upstream.conf.j2 @@ -0,0 +1,3 @@ +upstream k8s_tls { + server 127.0.0.1:443; +} diff --git a/ansible/mailserver/roles/nginx/templates/mail.conf.j2 b/ansible/mailserver/roles/nginx/templates/mail.conf.j2 index 8d76318..a42ca84 100644 --- a/ansible/mailserver/roles/nginx/templates/mail.conf.j2 +++ b/ansible/mailserver/roles/nginx/templates/mail.conf.j2 @@ -15,8 +15,7 @@ server { } server { - listen 443 ssl http2; - listen [::]:443 ssl http2; + listen 127.0.0.1:8443 ssl http2; server_name {{ nginx_server_name }}; ssl_certificate {{ nginx_tls_cert }}; @@ -94,8 +93,7 @@ server { } server { - listen 443 ssl http2; - listen [::]:443 ssl http2; + listen 127.0.0.1:8443 ssl http2; server_name {{ nginx_stalwart_server_name }}; ssl_certificate {{ nginx_tls_cert }}; diff --git a/ansible/mailserver/roles/nginx/templates/nginx.conf.j2 b/ansible/mailserver/roles/nginx/templates/nginx.conf.j2 new file mode 100644 index 0000000..d7b669e --- /dev/null +++ b/ansible/mailserver/roles/nginx/templates/nginx.conf.j2 @@ -0,0 +1,54 @@ +user www-data; +worker_processes auto; +pid /run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; + +events { + worker_connections 768; +} + +http { + sendfile on; + tcp_nopush on; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + gzip on; + + include /etc/nginx/sites-enabled/*; +} + +stream { + log_format stream '$remote_addr [$time_local] ' + '$protocol $status $bytes_sent $bytes_received ' + '$session_time "$ssl_preread_server_name"'; + access_log /var/log/nginx/stream.log stream; + + map $ssl_preread_server_name $tls_backend { +{% for domain in nginx_local_tls_domains %} + {{ domain }} local_tls; +{% endfor %} + default k8s_tls; + } + + upstream local_tls { + server 127.0.0.1:8443; + } + + include /etc/nginx/stream.d/*.conf; + + server { + listen 443; + listen [::]:443; + ssl_preread on; + proxy_pass $tls_backend; + } +} diff --git a/dns/domains/rubenhensen.nl.yaml b/dns/domains/rubenhensen.nl.yaml index 20b6ce4..df1214e 100644 --- a/dns/domains/rubenhensen.nl.yaml +++ b/dns/domains/rubenhensen.nl.yaml @@ -2,7 +2,7 @@ records: - name: "@" expire: 86400 type: A - content: "62.41.87.114" + content: "46.224.26.65" - name: mail expire: 86400 type: A diff --git a/ip-updater/cronjob.yaml b/ip-updater/cronjob.yaml index 273e7a2..1a010de 100644 --- a/ip-updater/cronjob.yaml +++ b/ip-updater/cronjob.yaml @@ -19,8 +19,6 @@ spec: apk add --no-cache openssh-client curl > /dev/null 2>&1 cp /ssh-key/private_key /tmp/ssh_key chmod 600 /tmp/ssh_key - echo "Key starts with: $(head -1 /tmp/ssh_key)" - wc -c /tmp/ssh_key IP=$(curl -s --max-time 10 https://api.ipify.org) if [ -z "$IP" ]; then echo "Failed to get external IP"