- nginx: nginx-prometheus-exporter gated by nginx_exporter_enabled, deploys loopback-only stub_status (8090), exporter on 9113 - postgres: postgres_exporter gated by postgres_exporter_enabled, creates postgres_exporter role with pg_monitor, exporter on 9187 - valkey: redis_exporter gated by valkey_exporter_enabled, adds read-only ACL user to users.acl, exporter on 9121 Each exporter follows the nut pattern (tasks/exporter.yml included from main.yml, OS vars, 0600 secret env files, password asserts).
Nginx Role
Installs and configures Nginx as a reverse proxy for web applications with modular vhost management.
Features
- Modular vhost configuration via
/etc/nginx/conf.d/ - Zero-downtime reloads
- Configurable logging backend (journald or traditional files)
- Automatic logrotate for file-based logging
- SSL/TLS configuration
- Native ACME/Let's Encrypt support (Nginx 1.25.0+)
- Transparent proxy forwarding (HTTP/HTTPS to other hosts)
- Catch-all
default_serverthat rejects unknown SNI/Host with444
Catch-all default_server
A 00-default.conf vhost is deployed and marked default_server on both
ports 80 and 443. It uses a self-signed cert (/etc/nginx/ssl/default.crt)
and returns 444 (close connection) for any request whose SNI/Host does
not match an explicit vhost. ACME HTTP-01 challenges (/.well-known/acme-challenge/)
are still answered on port 80 so Certbot keeps working for new hostnames.
Without this, clients hitting the server IP directly (or doing HTTP/2 connection coalescing across vhosts sharing the same IP) would receive the certificate of the first vhost loaded alphabetically, leaking that hostname and breaking TLS verification on other vhosts.
Disable with nginx_default_server_enabled: false.
Prometheus exporter
Optionally exposes nginx metrics (active connections, requests/sec) for
Prometheus via nginx-prometheus-exporter, which scrapes a loopback-only
stub_status endpoint this role deploys. Enable it:
nginx_exporter_enabled: true
The exporter binds to 127.0.0.1:9113; the stub_status block listens on
127.0.0.1:8090 and denies non-localhost clients. Pair it with a scrape job:
prometheus_scrape_configs:
- job_name: 'nginx'
static_configs:
- targets: ['127.0.0.1:9113']
Service Integration Pattern
Each service role should deploy its own vhost config:
In service role tasks:
- name: Deploy nginx vhost
ansible.builtin.template:
src: nginx-vhost.conf.j2
dest: /etc/nginx/conf.d/myservice.conf
validate: nginx -t
when: myservice_nginx_enabled
notify: Reload nginx
- name: Remove nginx vhost when disabled
ansible.builtin.file:
path: /etc/nginx/conf.d/myservice.conf
state: absent
when: not myservice_nginx_enabled
notify: Reload nginx
Transparent Proxy Forwarding
Forward TCP traffic from this Nginx instance to services on other hosts using the stream module (layer 4 proxy).
Configuration:
nginx_forwarder:
"blog.hello.com":
forward_to: "my.host.lan"
http: true # Forward port 80 (default: true)
https: true # Forward port 443 (default: true)
How it works:
- Stream-based TCP proxy (layer 4, not HTTP layer 7)
- No protocol inspection - just forwards raw TCP packets
- HTTPS passes through encrypted - backend host handles TLS termination
- HTTP also uses stream (simpler, but no HTTP features like headers/logging)
Use case: Omega (gateway) forwards all traffic to Andromeda (internal server) that handles its own TLS certificates.
Important notes:
- Stream configs deployed to
/etc/nginx/streams.d/ - No HTTP logging (stream doesn't understand HTTP protocol)
- No X-Forwarded-For headers (transparent TCP forwarding)
- Only ONE domain can use port 443 forwarding (TCP port limitation)
Logging Backends
journald (default):
- Logs sent to systemd journal via syslog
- View:
journalctl -u nginx -f
file:
- Traditional
/var/log/nginx/*.logfiles - Automatic logrotate configuration
Switch via nginx_log_backend variable.
Hands-on Commands
# Test configuration
nginx -t
# Reload (zero downtime)
systemctl reload nginx
# View logs (journald)
journalctl -u nginx -f
journalctl -u nginx -n 100
journalctl -u nginx -p err
# View logs (file)
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
# List loaded vhosts
ls -la /etc/nginx/conf.d/
# List stream forwarders
ls -la /etc/nginx/streams.d/
Configuration Variables
See defaults/main.yml for all available variables.