summaryrefslogtreecommitdiff
path: root/playbooks/roles/outbound/templates/proxy
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2025-04-27 21:15:30 -0700
committerElizabeth Hunt <me@liz.coffee>2025-04-27 21:25:52 -0700
commitdaef0cf448af17357b552245f39067a9d340ce3d (patch)
treef65a660f7232f057b0c14e477c166006bfb83f87 /playbooks/roles/outbound/templates/proxy
parent1dcdfe34a74708f88aad68af965f4bb5c79adff1 (diff)
downloadinfra-daef0cf448af17357b552245f39067a9d340ce3d.tar.gz
infra-daef0cf448af17357b552245f39067a9d340ce3d.zip
Waow
Diffstat (limited to 'playbooks/roles/outbound/templates/proxy')
-rw-r--r--playbooks/roles/outbound/templates/proxy/docker-compose.yml53
-rwxr-xr-xplaybooks/roles/outbound/templates/proxy/headscale/headscale-client.sh14
-rw-r--r--playbooks/roles/outbound/templates/proxy/nginx/conf.d/bin.conf (renamed from playbooks/roles/outbound/templates/proxy/sites-enabled/bin.conf)0
-rw-r--r--playbooks/roles/outbound/templates/proxy/nginx/conf.d/default.conf (renamed from playbooks/roles/outbound/templates/proxy/sites-enabled/default.conf)4
-rw-r--r--playbooks/roles/outbound/templates/proxy/nginx/conf.d/idm.conf (renamed from playbooks/roles/outbound/templates/proxy/sites-enabled/idm.conf)0
-rw-r--r--playbooks/roles/outbound/templates/proxy/nginx/conf.d/kanban.conf (renamed from playbooks/roles/outbound/templates/proxy/sites-enabled/kanban.conf)0
-rw-r--r--playbooks/roles/outbound/templates/proxy/nginx/conf.d/mail.conf (renamed from playbooks/roles/outbound/templates/proxy/sites-enabled/mail.conf)0
-rw-r--r--playbooks/roles/outbound/templates/proxy/nginx/conf.d/notes.conf (renamed from playbooks/roles/outbound/templates/proxy/sites-enabled/notes.conf)0
-rwxr-xr-xplaybooks/roles/outbound/templates/proxy/nginx/dont-die-until-conn-closed.sh56
-rw-r--r--playbooks/roles/outbound/templates/proxy/nginx/nginx.conf30
-rw-r--r--playbooks/roles/outbound/templates/proxy/nginx/toplevel.conf.d/stream.conf56
-rwxr-xr-xplaybooks/roles/outbound/templates/proxy/nginx/wait-for-bridge.sh33
-rw-r--r--playbooks/roles/outbound/templates/proxy/toplevel.conf.d/stream.conf38
13 files changed, 236 insertions, 48 deletions
diff --git a/playbooks/roles/outbound/templates/proxy/docker-compose.yml b/playbooks/roles/outbound/templates/proxy/docker-compose.yml
index 9642d6a..c5aa3ac 100644
--- a/playbooks/roles/outbound/templates/proxy/docker-compose.yml
+++ b/playbooks/roles/outbound/templates/proxy/docker-compose.yml
@@ -1,36 +1,69 @@
+---
+
services:
headscale-client:
image: tailscale/tailscale:latest
environment:
+ - DEPLOYMENT_TIME={{ now() }}
- TS_AUTHKEY={{ headscale_user_auth_key }}
- TS_EXTRA_ARGS=--login-server=https://{{ headscale_host }} --accept-routes --accept-dns --stateful-filtering=false
- TS_STATE_DIR=/var/lib/tailscale
- TS_USERSPACE=false
- TZ={{ timezone }}
-
- - VIRTUAL_HOST=*.{{ domain }},{{ domain }}
- - VIRTUAL_PORT=80
- - LETSENCRYPT_HOST=*.{{ domain }},{{ domain }}
- hostname: headscale-outbound
restart: unless-stopped
+ healthcheck:
+ test: ["CMD-SHELL", "tailscale status"]
+ interval: 1s
+ timeout: 5s
+ retries: 10
+ hostname: headscale-outbound
cap_add:
- NET_ADMIN
- SYS_ADMIN
volumes:
- ./data:/var/lib/tailscale
+ - ./headscale/headscale-client.sh:/headscale-client.sh
- /dev/net/tun:/dev/net/tun
networks:
- - proxy
- proxy:
+ - internal_subnet_router # magic.
+ sysctls:
+ - net.ipv4.ip_forward=1
+ entrypoint: ["/bin/sh"]
+ command: /headscale-client.sh
+
+ {{ vpn_proxy_filter_container_name }}:
image: nginx:latest
- network_mode: service:headscale-client
+ entrypoint: ["/bin/sh"]
+ command: /wait-for-bridge.sh
+ pre_stop:
+ - command: /dont-die-until-conn-closed.sh
+ cap_add:
+ - NET_ADMIN # to modify the routing table
+ environment:
+ - DEPLOYMENT_TIME={{ now() }}
+ - VIRTUAL_HOST=*.{{ domain }},{{ domain }}
+ - VIRTUAL_PORT=80
+ - LETSENCRYPT_HOST=*.{{ domain }},{{ domain }}
+ healthcheck:
+ test: ["CMD", "curl", "http://localhost/health"]
+ interval: 10s
+ timeout: 5s
+ retries: 3
depends_on:
- headscale-client
volumes:
- - ./sites-enabled:/etc/nginx/conf.d
- - ./toplevel.conf.d:/etc/nginx/toplevel.conf.d
+ - ./nginx/nginx.conf:/etc/nginx/nginx.conf
+ - ./nginx/conf.d:/etc/nginx/conf.d
+ - ./nginx/toplevel.conf.d:/etc/nginx/toplevel.conf.d
+ - ./nginx/wait-for-bridge.sh:/wait-for-bridge.sh
+ - ./nginx/dont-die-until-conn-closed.sh:/dont-die-until-conn-closed.sh
+ networks:
+ - proxy
+ - internal_subnet_router
networks:
+ internal_subnet_router:
+ driver: bridge
proxy:
external: true
diff --git a/playbooks/roles/outbound/templates/proxy/headscale/headscale-client.sh b/playbooks/roles/outbound/templates/proxy/headscale/headscale-client.sh
new file mode 100755
index 0000000..1ce0acb
--- /dev/null
+++ b/playbooks/roles/outbound/templates/proxy/headscale/headscale-client.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+/usr/local/bin/containerboot &
+
+while ! tailscale status > /dev/null 2>&1; do
+ sleep 1
+ echo '[+] Waiting for tailscale status to be up...'
+done
+
+echo '[+] Tailscale is up. Enabling NAT...'
+iptables -t nat -A POSTROUTING -o tailscale0 -j MASQUERADE
+echo '[+] Done.'
+
+tail -f /dev/null
diff --git a/playbooks/roles/outbound/templates/proxy/sites-enabled/bin.conf b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/bin.conf
index 3c5682d..3c5682d 100644
--- a/playbooks/roles/outbound/templates/proxy/sites-enabled/bin.conf
+++ b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/bin.conf
diff --git a/playbooks/roles/outbound/templates/proxy/sites-enabled/default.conf b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/default.conf
index d127cc5..f4a8007 100644
--- a/playbooks/roles/outbound/templates/proxy/sites-enabled/default.conf
+++ b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/default.conf
@@ -4,4 +4,8 @@ server {
location / {
return 404;
}
+
+ location /health {
+ return 200;
+ }
}
diff --git a/playbooks/roles/outbound/templates/proxy/sites-enabled/idm.conf b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/idm.conf
index c85ebcf..c85ebcf 100644
--- a/playbooks/roles/outbound/templates/proxy/sites-enabled/idm.conf
+++ b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/idm.conf
diff --git a/playbooks/roles/outbound/templates/proxy/sites-enabled/kanban.conf b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/kanban.conf
index b668310..b668310 100644
--- a/playbooks/roles/outbound/templates/proxy/sites-enabled/kanban.conf
+++ b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/kanban.conf
diff --git a/playbooks/roles/outbound/templates/proxy/sites-enabled/mail.conf b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/mail.conf
index c810f5a..c810f5a 100644
--- a/playbooks/roles/outbound/templates/proxy/sites-enabled/mail.conf
+++ b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/mail.conf
diff --git a/playbooks/roles/outbound/templates/proxy/sites-enabled/notes.conf b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/notes.conf
index f7937dd..f7937dd 100644
--- a/playbooks/roles/outbound/templates/proxy/sites-enabled/notes.conf
+++ b/playbooks/roles/outbound/templates/proxy/nginx/conf.d/notes.conf
diff --git a/playbooks/roles/outbound/templates/proxy/nginx/dont-die-until-conn-closed.sh b/playbooks/roles/outbound/templates/proxy/nginx/dont-die-until-conn-closed.sh
new file mode 100755
index 0000000..967c2c0
--- /dev/null
+++ b/playbooks/roles/outbound/templates/proxy/nginx/dont-die-until-conn-closed.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+echo "[/] sleeping to wait for some time for container to be marked as stop."
+# https://stackoverflow.com/a/45146086
+sleep 3
+
+pid_file="/run/nginx.pid"
+max_wait_seconds=30
+
+if [ ! -f "$pid_file" ]; then
+ echo "[!] Nginx PID file not found at $pid_file. Assuming Nginx not running or already stopped."
+ exit 0
+fi
+
+PID=$(cat "$pid_file")
+
+# Validate PID
+if [ -z "$PID" ] || ! [[ "$PID" =~ ^[0-9]+$ ]]; then
+ echo "[!] Invalid PID found in $pid_file: '$PID'"
+ exit 1
+fi
+
+# Check if the process actually exists before sending quit
+# kill -0 PID checks if a signal can be sent.
+if ! kill -0 "$PID" 2>/dev/null; then
+ echo "[!] Nginx process $PID not found or already stopped."
+ exit 0 # Exit successfully
+fi
+
+echo "[/] sending signal to nginx (PID: $PID) to quit"
+nginx -s quit
+
+start_time=$SECONDS
+echo "[/] Waiting for Nginx (PID: $PID) to stop (max ${max_wait_seconds}s)..."
+
+while [ -d /proc/$PID ]; do
+ current_time=$SECONDS
+ elapsed_time=$((current_time - start_time))
+
+ if [ "$elapsed_time" -ge "$max_wait_seconds" ]; then
+ echo "[!] Timeout: Nginx process $PID did not stop within ${max_wait_seconds} seconds."
+ echo "[!] Sending SIGKILL to PID $PID."
+ kill -9 "$PID" 2>/dev/null
+
+ exit 1
+ fi
+
+ sleep 0.5
+ if (( $(echo "$elapsed_time % 5" | bc) == 0 )); then
+ echo "[/] Nginx (PID: $PID) still running (waited ${elapsed_time}s)..."
+ fi
+done
+
+echo "[+] Nginx process $PID stopped gracefully."
+echo "[+] done. goodbye."
+exit 0
diff --git a/playbooks/roles/outbound/templates/proxy/nginx/nginx.conf b/playbooks/roles/outbound/templates/proxy/nginx/nginx.conf
new file mode 100644
index 0000000..32feb3a
--- /dev/null
+++ b/playbooks/roles/outbound/templates/proxy/nginx/nginx.conf
@@ -0,0 +1,30 @@
+user www-data;
+worker_processes 4;
+pid /run/nginx.pid;
+# load_module modules/ndk_http_module.so;
+# load_module modules/ngx_http_set_misc_module.so;
+
+events {
+ worker_connections 768;
+}
+
+include /etc/nginx/toplevel.conf.d/*.conf;
+
+http {
+ charset utf-8;
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 65;
+ types_hash_max_size 2048;
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ access_log /var/log/nginx/access.log;
+ error_log /var/log/nginx/error.log;
+
+ gzip on;
+ gzip_disable "msie6";
+
+ include /etc/nginx/conf.d/*.conf;
+}
diff --git a/playbooks/roles/outbound/templates/proxy/nginx/toplevel.conf.d/stream.conf b/playbooks/roles/outbound/templates/proxy/nginx/toplevel.conf.d/stream.conf
new file mode 100644
index 0000000..193e65a
--- /dev/null
+++ b/playbooks/roles/outbound/templates/proxy/nginx/toplevel.conf.d/stream.conf
@@ -0,0 +1,56 @@
+stream {
+ log_format basic '$proxy_protocol_addr - [$time_local] '
+ '$protocol $status $bytes_sent $bytes_received '
+ '$session_time';
+ upstream imaps {
+ server {{ loadbalancer_ip }}:993;
+ }
+ upstream smtps {
+ server {{ loadbalancer_ip }}:465;
+ }
+ upstream smtptls {
+ server {{ loadbalancer_ip }}:587;
+ }
+ upstream smtp {
+ server {{ loadbalancer_ip }}:25;
+ }
+ upstream managesieve {
+ server {{ loadbalancer_ip }}:4190;
+ }
+
+ server {
+ set_real_ip_from {{ docker_network }};
+ listen 993 proxy_protocol;
+
+ proxy_pass imaps;
+ proxy_protocol on;
+ }
+ server {
+ set_real_ip_from {{ docker_network }};
+ listen 25 proxy_protocol;
+
+ proxy_pass smtp;
+ proxy_protocol on;
+ }
+ server {
+ set_real_ip_from {{ docker_network }};
+ listen 587 proxy_protocol;
+
+ proxy_pass smtptls;
+ proxy_protocol on;
+ }
+ server {
+ set_real_ip_from {{ docker_network }};
+ listen 465 proxy_protocol;
+
+ proxy_pass smtps;
+ proxy_protocol on;
+ }
+ server {
+ set_real_ip_from {{ docker_network }};
+ listen 4190 proxy_protocol;
+
+ proxy_pass managesieve;
+ proxy_protocol on;
+ }
+}
diff --git a/playbooks/roles/outbound/templates/proxy/nginx/wait-for-bridge.sh b/playbooks/roles/outbound/templates/proxy/nginx/wait-for-bridge.sh
new file mode 100755
index 0000000..da273a9
--- /dev/null
+++ b/playbooks/roles/outbound/templates/proxy/nginx/wait-for-bridge.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+set -e
+
+echo "[+] Waiting for headscale-client to be resolvable..."
+
+# Loop until headscale-client IP is found or timeout
+timeout=30
+start_time=$(date +%s)
+
+HEADSCALE_IP=""
+while [ -z "$HEADSCALE_IP" ]; do
+ HEADSCALE_IP=$(getent hosts headscale-client | awk '{ print $1 }' | head -n 1)
+ current_time=$(date +%s)
+ if [ $((current_time - start_time)) -ge $timeout ]; then
+ echo "[-] Timeout waiting for headscale-client DNS resolution." >&2
+ exit 1
+ fi
+ if [ -z "$HEADSCALE_IP" ]; then
+ sleep 1
+ fi
+done
+
+echo "[+] Found headscale-client IP: $HEADSCALE_IP"
+echo "[+] Attempting to modify routing table..."
+
+apt update && apt install -y iproute2
+ip route del default || echo "[-] Warning: Failed to delete default route (maybe none existed)."
+ip route add default via $HEADSCALE_IP
+echo "[+] Default route set via $HEADSCALE_IP."
+
+echo "[+] Starting Nginx..."
+nginx -g "daemon off;"
diff --git a/playbooks/roles/outbound/templates/proxy/toplevel.conf.d/stream.conf b/playbooks/roles/outbound/templates/proxy/toplevel.conf.d/stream.conf
deleted file mode 100644
index 68d5445..0000000
--- a/playbooks/roles/outbound/templates/proxy/toplevel.conf.d/stream.conf
+++ /dev/null
@@ -1,38 +0,0 @@
-stream {
- upstream imaps {
- server {{ loadbalancer_ip }}:993;
- }
- upstream smtps {
- server {{ loadbalancer_ip }}:465;
- }
- upstream smtptls {
- server {{ loadbalancer_ip }}:587;
- }
- upstream smtp {
- server {{ loadbalancer_ip }}:25;
- }
- upstream managesieve {
- server {{ loadbalancer_ip }}:4190;
- }
-
- server {
- listen 993;
- proxy_pass imaps;
- }
- server {
- listen 25;
- proxy_pass smtp;
- }
- server {
- listen 587;
- proxy_pass smtptls;
- }
- server {
- listen 465;
- proxy_pass smtps;
- }
- server {
- listen 4190;
- proxy_pass managesieve;
- }
-}