Initial commit
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
# nginx (Ansible role)
|
||||
|
||||
Installs and configures nginx for **simple homelab / local-network** setups, where most
|
||||
sites are "proxy a domain to a backend over HTTPS" and share a single wildcard cert.
|
||||
|
||||
This role exists because most of my nginx configs were nearly identical — same SSL
|
||||
params, same proxy headers, same redirect-to-HTTPS pattern. The role captures that
|
||||
shared shape, so each new service is a few lines of YAML instead of a copy-pasted
|
||||
server block.
|
||||
|
||||
**Not for production.** No Let's Encrypt automation, no per-vhost cert provisioning,
|
||||
no cleanup for sites removed from inventory, snakeoil cert as default. Override what
|
||||
you need.
|
||||
|
||||
Tested on Debian (bookworm/trixie) and Ubuntu (jammy/noble).
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
```yaml
|
||||
- hosts: nginx
|
||||
become: true
|
||||
roles:
|
||||
- role: nginx
|
||||
vars:
|
||||
# Override the default snakeoil cert with your real one
|
||||
nginx_ssl_certificate: /etc/nginx/ssl/lab.local/fullchain.pem
|
||||
nginx_ssl_certificate_key: /etc/nginx/ssl/lab.local/privkey.pem
|
||||
|
||||
nginx_sites:
|
||||
- name: default # keep the catch-all
|
||||
template_path: site-configs/default.conf.j2
|
||||
|
||||
- name: vaultwarden # your service
|
||||
domain_names:
|
||||
- vault.lab.local
|
||||
upstream_url: http://192.168.1.10:8080
|
||||
```
|
||||
|
||||
That's it. `vault.lab.local` now serves over HTTPS, redirects plain HTTP → HTTPS,
|
||||
uses the shared cert, and proxies everything to `192.168.1.10:8080`.
|
||||
|
||||
---
|
||||
|
||||
## Per-site options (`nginx_sites[*]`)
|
||||
|
||||
| Key | Type | Default | Notes |
|
||||
|------------------------|----------|----------------------------------|-----------------------------------------------------------------------|
|
||||
| `name` | string | **required** | Filename in `sites-available/`. |
|
||||
| `domain_names` | list | **required** * | Values for `server_name`. |
|
||||
| `upstream_url` | string | **required** * | `proxy_pass` target (e.g. `http://host:port`). |
|
||||
| `ssl` | bool | `true` | Enable HTTPS listener + cert. |
|
||||
| `allow_http` | bool | `false` | Also serve content over plain HTTP. By default HTTP → 301 → HTTPS. |
|
||||
| `websockets` | bool | `false` | Include `websockets.conf` (upgrade headers). |
|
||||
| `max_upload_size` | string | unset | `client_max_body_size` value, e.g. `"50m"`. |
|
||||
| `extra_parameters` | string | unset | Freeform nginx directives injected into the server block. |
|
||||
| `https_port` | int | `443` | Override HTTPS listen port. |
|
||||
| `http_port` | int | `80` | Override HTTP listen port. |
|
||||
| `ssl_certificate` | path | `nginx_ssl_certificate` | Per-site cert override. |
|
||||
| `ssl_certificate_key` | path | `nginx_ssl_certificate_key` | Per-site key override. |
|
||||
| `enabled` | bool | `nginx_site_enabled_by_default` | Create the `sites-enabled/` symlink. Setting `false` removes it. |
|
||||
| `template_path` | string | `nginx_site_config_template` | Use a custom template (path relative to `templates/`). |
|
||||
| `conf_file` | path | unset | Use a static file instead of the template (path relative to playbook).|
|
||||
|
||||
\* Required when using the built-in template. If you supply `conf_file` or a custom
|
||||
`template_path`, only `name` is required.
|
||||
|
||||
---
|
||||
|
||||
## Role variables
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
|---------------------------------------|-----------------------------------------------|----------------------------------------------------------------------|
|
||||
| `nginx_ssl_certificate` | `/etc/ssl/certs/ssl-cert-snakeoil.pem` | Default cert path for all sites. |
|
||||
| `nginx_ssl_certificate_key` | `/etc/ssl/private/ssl-cert-snakeoil.key` | Default key path. |
|
||||
| `nginx_resolver` | `127.0.0.53 valid=300s` | Global DNS resolver (used by OCSP stapling). Override for LAN DNS. |
|
||||
| `nginx_resolver_timeout` | `5s` | |
|
||||
| `nginx_site_enabled_by_default` | `true` | Whether sites without an explicit `enabled` get symlinked. |
|
||||
| `nginx_delete_default_site_config` | `false` | Delete Debian's `sites-available/default` (only matters if you remove the `default` entry from `nginx_sites`). |
|
||||
| `nginx_site_config_template` | `nginx-site.conf.j2` | Default template used when a site has no `template_path`/`conf_file`.|
|
||||
| `nginx_sites` | one entry (the catch-all `default` site) | Your list of sites. |
|
||||
| `nginx_snippets` | `[proxy-headers, ssl-params, websockets, fastcgi-php]` | Static snippets dropped into `/etc/nginx/snippets/`. |
|
||||
| `nginx_conf_d_templates` | `[resolver.conf]` | Templated files rendered into `/etc/nginx/conf.d/`. |
|
||||
|
||||
Path variables (`nginx_site_config_path`, `nginx_site_enabled_path`,
|
||||
`nginx_snippets_path`, `nginx_conf_d_path`) exist for completeness and default to
|
||||
Debian's canonical locations. You usually shouldn't touch them.
|
||||
|
||||
---
|
||||
|
||||
## The default catch-all site
|
||||
|
||||
The shipped default entry (`name: default`) renders
|
||||
`templates/site-configs/default.conf.j2`, which:
|
||||
|
||||
- Listens on `:80` with `default_server`, 301-redirects any unknown `Host:` to HTTPS.
|
||||
- Listens on `:443 ssl http2` with `default_server`, returns `404`.
|
||||
|
||||
It exists so unknown-host traffic doesn't leak one of your real sites' certs/content
|
||||
via SNI scans. Keep it if you have more than one site; remove it (and set
|
||||
`nginx_delete_default_site_config: true`) if you have exactly one.
|
||||
|
||||
---
|
||||
|
||||
## Custom static configs
|
||||
|
||||
For sites that don't fit the template — e.g. a static file server, a non-proxy
|
||||
site, an upstream block — write the full nginx config yourself and point at it:
|
||||
|
||||
```yaml
|
||||
- name: media
|
||||
conf_file: site-configs/media.conf # path relative to your playbook
|
||||
```
|
||||
|
||||
The role copies it verbatim into `sites-available/`.
|
||||
|
||||
---
|
||||
|
||||
## Caveats
|
||||
|
||||
- **Snakeoil default cert.** The role works out of the box but presents an untrusted
|
||||
self-signed cert. Set `nginx_ssl_certificate(_key)` to your real cert before
|
||||
serving anything real.
|
||||
- **One shared cert by default.** A single wildcard is the assumed homelab pattern.
|
||||
Per-site override via `ssl_certificate` / `ssl_certificate_key` works for the
|
||||
exceptions.
|
||||
- **No removal cleanup.** If you delete a site from `nginx_sites`, the existing
|
||||
`sites-available/<name>` and `sites-enabled/<name>` are not removed. Clean up
|
||||
manually or set `enabled: false` and let the symlink task remove the link.
|
||||
- **Debian/Ubuntu only.** Paths assume the Debian-style `sites-available/` +
|
||||
`sites-enabled/` split. Won't work on Alpine, RHEL, etc. without surgery.
|
||||
- **No Let's Encrypt / ACME.** Bring your own certs.
|
||||
- **Resolver default assumes systemd-resolved.** Override `nginx_resolver` if you
|
||||
use a different local resolver (e.g. `"dns.home valid=300s"`).
|
||||
Reference in New Issue
Block a user