Add shared nginx-proxy role; deploy Hermes in Docker; rename Paperclip
nginx-proxy (new role): - Shared nginx + certbot under /opt/nginx, replacing the copies that lived inside the Paperclip compose project - Apps publish via tasks_from: add_vhost (cert marker -> issue cert -> write vhost -> nginx -t -> reload); a vhost that fails nginx -t is rolled back - Certs issued one per domain via Cloudflare DNS challenge; domains registered as marker files in cert-domains/; optional LE staging - Stock nginx.conf plus conf.d (directory mounts, not single-file mounts); catch-all server drops unknown Host/SNI - Containers renamed to nginx and certbot hermes_docker (new role): - Official Hermes image, host networking, gateway and dashboard bound to loopback and published through nginx-proxy - Dashboard login via basic-auth provider, secrets from the vault - Main model set from hermes_model (fantasmic endpoint, key from vault); config.yaml overrides are merged from a 0600 staged file that is removed afterwards, so the key never appears in a command line - Data dir owner-only (HERMES_HOME_MODE=0700) paperclip-docker: - Remove nginx, certbot and docker-compose download tasks; deploy with community.docker.docker_compose_v2 (idempotent, remove_orphans) - Stop passing the Cloudflare token and certbot email to the Paperclip container via env_file - Bind Postgres to 127.0.0.1 (host networking exposed it on all interfaces); stop chowning pgdata, which the postgres image owns - Handler recreates the paperclip service so .env changes apply - Domain m-v.wdw-labs.cloud -> cranium-command.wdw-labs.cloud Playbooks: - Add day1_deploy_nginx_proxy.yml and day1_deploy_hermes_docker.yml - deploy_paperclip_stack.yml: run nginx-proxy before paperclip-docker, CLI-based container checks (no Docker SDK dependency) - Remove deploy-hermes.yml Host vars: add nginx_proxy_certbot_email and nginx_proxy_certbot_staging (staging stays on until the switch to real certs).
This commit is contained in:
1 parent
5b48536c32
commit
881e2e24a8
37 files changed
+1683
-755
No files matched your search
@@ -0,0 +1,31 @@
|
||||
# Managed by Ansible (nginx-proxy role)
|
||||
# Included inside the stock nginx.conf http { } block, so these are http-level.
|
||||
server_tokens off;
|
||||
client_max_body_size {{ nginx_proxy_client_max_body_size }};
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# Catch-all: unknown Host headers get nothing, and unknown SNI is rejected
|
||||
# before any certificate is presented.
|
||||
server {
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
access_log off;
|
||||
|
||||
location = /nginx-health {
|
||||
return 200 "ok\n";
|
||||
}
|
||||
location / {
|
||||
return 444;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl default_server;
|
||||
server_name _;
|
||||
ssl_reject_handshake on;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
# Managed by Ansible (nginx-proxy role)
|
||||
services:
|
||||
certbot:
|
||||
image: {{ nginx_proxy_certbot_image }}
|
||||
container_name: {{ nginx_proxy_certbot_container }}
|
||||
volumes:
|
||||
- {{ nginx_proxy_certs_dir }}:/etc/letsencrypt
|
||||
- {{ nginx_proxy_scripts_dir }}:/scripts:ro
|
||||
- {{ nginx_proxy_domains_dir }}:/etc/cert-domains.d:ro
|
||||
environment:
|
||||
CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_API_TOKEN}
|
||||
CERTBOT_EMAIL: ${CERTBOT_EMAIL}
|
||||
CERTBOT_STAGING: "{{ '1' if nginx_proxy_certbot_staging | bool else '0' }}"
|
||||
entrypoint: /bin/sh
|
||||
command:
|
||||
- -c
|
||||
- |
|
||||
while true; do
|
||||
/scripts/certbot-init.sh || echo "issuance failed; will retry next cycle"
|
||||
certbot renew --quiet
|
||||
sleep 12h
|
||||
done
|
||||
restart: unless-stopped
|
||||
|
||||
nginx:
|
||||
image: {{ nginx_proxy_nginx_image }}
|
||||
container_name: {{ nginx_proxy_nginx_container }}
|
||||
network_mode: host
|
||||
volumes:
|
||||
# Directory mounts (not single files) so Ansible's atomic file
|
||||
# replacement is visible inside the container.
|
||||
- {{ nginx_proxy_conf_dir }}:/etc/nginx/conf.d:ro
|
||||
- {{ nginx_proxy_certs_dir }}:/etc/nginx/certs:ro
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
( while :; do sleep {{ nginx_proxy_reload_interval }}; nginx -s reload; done ) &
|
||||
exec nginx -g 'daemon off;'
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/nginx-health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
@@ -0,0 +1,3 @@
|
||||
# Managed by Ansible (nginx-proxy role)
|
||||
CLOUDFLARE_API_TOKEN={{ nginx_proxy_cloudflare_api_token }}
|
||||
CERTBOT_EMAIL={{ nginx_proxy_certbot_email }}
|
||||
@@ -0,0 +1,51 @@
|
||||
# Managed by Ansible (nginx-proxy role) - vhost: {{ vhost_name }}
|
||||
server {
|
||||
listen 80;
|
||||
server_name {{ vhost_domain }};
|
||||
return 301 https://{{ vhost_domain }}$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
{% if nginx_proxy_http2 | bool %}
|
||||
http2 on;
|
||||
{% endif %}
|
||||
server_name {{ vhost_domain }};
|
||||
|
||||
ssl_certificate /etc/nginx/certs/live/{{ vhost_domain }}/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/live/{{ vhost_domain }}/privkey.pem;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
location / {
|
||||
proxy_pass http://{{ vhost_upstream_host | default('127.0.0.1') }}:{{ vhost_upstream_port }};
|
||||
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_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout {{ vhost_proxy_timeout | default('60s') }};
|
||||
proxy_read_timeout {{ vhost_proxy_timeout | default('60s') }};
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
{% if vhost_health_path | default('') | length > 0 %}
|
||||
|
||||
location {{ vhost_health_path }} {
|
||||
proxy_pass http://{{ vhost_upstream_host | default('127.0.0.1') }}:{{ vhost_upstream_port }}{{ vhost_health_path }};
|
||||
access_log off;
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
Reference in new issue
Block a user