mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-30 15:28:12 +02:00
Renamed webserver roles to more speakable names
This commit is contained in:
31
roles/srv-proxy-core/README.md
Normal file
31
roles/srv-proxy-core/README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Nginx Docker Reverse Proxy 🚀
|
||||
|
||||
## Description
|
||||
|
||||
This Ansible role deploys **Nginx** as a high-performance [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) in front of Docker-hosted services.
|
||||
It provides automatic TLS integration, WebSocket support, and a flexible templating system for per-application configuration.
|
||||
|
||||
## Overview
|
||||
|
||||
Optimised for Arch Linux, the role installs Nginx, prepares opinionated configuration snippets and exposes a simple interface for other roles to drop in new virtual-hosts.
|
||||
It plays well with **Let’s Encrypt**, **OAuth2 Proxy**, and your existing Docker stack.
|
||||
|
||||
## Purpose
|
||||
|
||||
The goal of this role is to deliver a **hassle-free, production-ready reverse proxy** for self-hosted containers, suitable for homelabs and small-scale production workloads.
|
||||
|
||||
## Features
|
||||
|
||||
- **Automatic TLS & HSTS** — integrates with the *srv-https-stack* role for certificate management.
|
||||
- **Flexible vHost templates** — *basic* and *ws_generic* flavours cover standard HTTP and WebSocket applications.
|
||||
- **Security headers** — sensible defaults plus optional X-Frame-Options / CSP based on application settings.
|
||||
- **WebSocket & HTTP/2 aware** — upgrades, keep-alive tuning, and gzip already configured.
|
||||
- **OAuth2 gating** — drop-in support when *web-app-oauth2-proxy* is present.
|
||||
- **Modular includes** — headers, locations, and global snippets are factored for easy extension.
|
||||
|
||||
## Credits 📝
|
||||
|
||||
Developed and maintained by **Kevin Veen-Birkenbach**.
|
||||
More at <https://www.veen.world>
|
||||
|
||||
Part of the **Infinito.Nexus Project** — licensed under the [Infinito.Nexus NonCommercial License](https://s.infinito.nexus/license)
|
4
roles/srv-proxy-core/Todo.md
Normal file
4
roles/srv-proxy-core/Todo.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Todos
|
||||
- Optimize buffering
|
||||
- Optimize caching
|
||||
- Make 'proxy_hide_header Content-Security-Policy' optional by using more_header option. See [ChatGPT Conversation](https://chatgpt.com/share/6825cb39-8db8-800f-8886-0cebdfad575a)
|
24
roles/srv-proxy-core/meta/main.yml
Normal file
24
roles/srv-proxy-core/meta/main.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
galaxy_info:
|
||||
author: "Kevin Veen-Birkenbach"
|
||||
description: "Nginx reverse proxy front-end for local Docker applications."
|
||||
license: "Infinito.Nexus NonCommercial License"
|
||||
license_url: "https://s.infinito.nexus/license"
|
||||
company: |
|
||||
Kevin Veen-Birkenbach
|
||||
Consulting & Coaching Solutions
|
||||
https://www.veen.world
|
||||
min_ansible_version: "2.9"
|
||||
platforms:
|
||||
- name: Archlinux
|
||||
versions:
|
||||
- rolling
|
||||
galaxy_tags:
|
||||
- nginx
|
||||
- docker
|
||||
- reverse_proxy
|
||||
- web
|
||||
- automation
|
||||
- archlinux
|
||||
repository: https://s.infinito.nexus/code
|
||||
issue_tracker_url: https://s.infinito.nexus/issues
|
||||
documentation: "https://docs.infinito.nexus/"
|
9
roles/srv-proxy-core/tasks/main.yml
Normal file
9
roles/srv-proxy-core/tasks/main.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
- block:
|
||||
- name: Include dependencies
|
||||
include_role:
|
||||
name: '{{ item }}'
|
||||
loop:
|
||||
- srv-https-stack
|
||||
- srv-core
|
||||
- include_tasks: utils/run_once.yml
|
||||
when: run_once_srv_proxy_core is not defined
|
@@ -0,0 +1,2 @@
|
||||
add_header Content-Security-Policy "{{ applications | build_csp_header(application_id, domains) }}" always;
|
||||
proxy_hide_header Content-Security-Policy; # Todo: Make this optional
|
58
roles/srv-proxy-core/templates/location/README.md
Normal file
58
roles/srv-proxy-core/templates/location/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Nginx Location Templates
|
||||
|
||||
This directory contains Jinja2 templates for different Nginx `location` blocks, each designed to proxy and optimize different types of web traffic. These templates are used by the `srv-proxy-core` role to modularize and standardize reverse proxy configuration across a wide variety of applications.
|
||||
|
||||
---
|
||||
|
||||
## Overview of Files
|
||||
|
||||
### `html.conf.j2`
|
||||
- **Purpose:**
|
||||
Handles "normal" web traffic such as HTML pages, API endpoints, and general HTTP(S) requests.
|
||||
- **Features:**
|
||||
- Proxies requests to the backend service.
|
||||
- Optionally integrates with OAuth2 proxy for authentication.
|
||||
- Sets all necessary proxy headers.
|
||||
- Applies a Content Security Policy header.
|
||||
- Activates buffering for advanced features such as Lua-based string replacements.
|
||||
- Supports WebSocket upgrades for hybrid APIs.
|
||||
|
||||
---
|
||||
|
||||
### `ws.conf.j2`
|
||||
- **Purpose:**
|
||||
Handles WebSocket connections, enabling real-time features such as live updates or chats.
|
||||
- **Features:**
|
||||
- Sets all headers required for WebSocket upgrades.
|
||||
- Disables proxy buffering (required for WebSockets).
|
||||
- Uses `tcp_nodelay` for low latency.
|
||||
- Proxies traffic to the backend WebSocket server.
|
||||
|
||||
---
|
||||
|
||||
### `media.conf.j2`
|
||||
- **Purpose:**
|
||||
Proxies and caches static media files (images, icons, etc.).
|
||||
- **Features:**
|
||||
- Matches image file extensions (jpg, png, gif, webp, ico, svg, etc.).
|
||||
- Enables browser-side and proxy-side caching for efficient delivery.
|
||||
- Adds cache control headers and exposes the upstream cache status.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
These templates are intended for inclusion in larger Nginx configuration files via Jinja2.
|
||||
They modularize your configuration by separating HTML, WebSocket, and media proxying, allowing for clear, reusable, and maintainable reverse proxy logic.
|
||||
|
||||
- Use `html.conf.j2` for standard application HTTP/S endpoints.
|
||||
- Use `ws.conf.j2` for dedicated WebSocket endpoints.
|
||||
- Use `media.conf.j2` for efficient handling of static media content.
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Only enable WebSocket proxying (`ws.conf.j2`) for routes that actually require it, to avoid breaking buffering for standard HTTP.
|
||||
- Activate media proxying (`media.conf.j2`) if your application benefits from image caching at the proxy layer.
|
||||
- Keep templates modular for maintainability and scalability as your application grows.
|
2
roles/srv-proxy-core/templates/location/Todo.md
Normal file
2
roles/srv-proxy-core/templates/location/Todo.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# TODOS
|
||||
- ATM it seems like the media proxy isn't used. Propably it could make sense to activate it. -> Research it.
|
41
roles/srv-proxy-core/templates/location/html.conf.j2
Normal file
41
roles/srv-proxy-core/templates/location/html.conf.j2
Normal file
@@ -0,0 +1,41 @@
|
||||
{% set location = location | default("/")%}
|
||||
|
||||
location {{location}}
|
||||
{
|
||||
{% if oauth2_proxy_enabled | default(false) | bool %}
|
||||
{% include 'roles/web-app-oauth2-proxy/templates/following_directives.conf.j2'%}
|
||||
{% endif %}
|
||||
|
||||
{% set _loc = location|trim %}
|
||||
proxy_pass http://127.0.0.1:{{ http_port }}{{ (_loc|regex_replace('^(?:=|\\^~)\\s*','')) if not (_loc is match('^(@|~)')) else '' }};
|
||||
|
||||
# headers
|
||||
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-Port {{ WEB_PORT }};
|
||||
|
||||
{% include 'roles/srv-proxy-core/templates/headers/content_security_policy.conf.j2' %}
|
||||
|
||||
# WebSocket specific header
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# timeouts
|
||||
proxy_connect_timeout 5s;
|
||||
proxy_send_timeout 900s;
|
||||
proxy_read_timeout 900s;
|
||||
send_timeout 900s;
|
||||
|
||||
{% set proxy_lua_enabled = proxy_lua_enabled | default(true) | bool %}
|
||||
# Buffering needs to be activ, so that lua can do str replaces
|
||||
proxy_buffering {{ 'on' if proxy_lua_enabled else 'off' }};
|
||||
proxy_request_buffering {{ 'on' if proxy_lua_enabled else 'off' }};
|
||||
|
||||
{% if proxy_lua_enabled %}
|
||||
proxy_set_header Accept-Encoding "";
|
||||
{% include 'roles/sys-srv-web-inj-compose/templates/location.lua.j2'%}
|
||||
{% endif %}
|
||||
}
|
12
roles/srv-proxy-core/templates/location/media.conf.j2
Normal file
12
roles/srv-proxy-core/templates/location/media.conf.j2
Normal file
@@ -0,0 +1,12 @@
|
||||
location ~* \.(jpg|jpeg|png|gif|webp|ico|svg)$ {
|
||||
# Cache in browser
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, max-age=2592000, immutable";
|
||||
|
||||
# Cache on reverse proxy side
|
||||
proxy_pass http://127.0.0.1:{{ http_port }};
|
||||
proxy_cache imgcache;
|
||||
proxy_cache_valid 200 302 60m;
|
||||
proxy_cache_valid 404 1m;
|
||||
add_header X-Proxy-Cache $upstream_cache_status;
|
||||
}
|
13
roles/srv-proxy-core/templates/location/upload.conf.j2
Normal file
13
roles/srv-proxy-core/templates/location/upload.conf.j2
Normal file
@@ -0,0 +1,13 @@
|
||||
location {{ location_upload }} {
|
||||
proxy_pass http://127.0.0.1:{{ http_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;
|
||||
client_max_body_size {{ client_max_body_size }};
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_read_timeout 120s;
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_send_timeout 120s;
|
||||
}
|
14
roles/srv-proxy-core/templates/location/ws.conf.j2
Normal file
14
roles/srv-proxy-core/templates/location/ws.conf.j2
Normal file
@@ -0,0 +1,14 @@
|
||||
location {{ location_ws }} {
|
||||
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_pass http://127.0.0.1:{{ ws_port }};
|
||||
|
||||
# Proxy buffering needs to be disabled for websockets.
|
||||
proxy_buffering off;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
tcp_nodelay on;
|
||||
}
|
78
roles/srv-proxy-core/templates/vhost/README.md
Normal file
78
roles/srv-proxy-core/templates/vhost/README.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Nginx vHost Templates: Basic vs. WebSocket (ws_generic)
|
||||
|
||||
This directory provides two Nginx server templates for reverse proxying Dockerized applications behind Nginx:
|
||||
- `basic.conf.j2`
|
||||
- `ws_generic.conf.j2`
|
||||
|
||||
---
|
||||
|
||||
## When to Use Which Template?
|
||||
|
||||
### 1. `basic.conf.j2`
|
||||
**Use this template for standard HTTP/S applications.**
|
||||
It is optimized for typical web applications (e.g., static sites, PHP, Node.js, Django, etc.) that do **not** require persistent, bidirectional WebSocket connections.
|
||||
|
||||
- **Features:**
|
||||
- HTTP/2 support, TLS/SSL integration
|
||||
- Reverse proxy with buffering enabled (`proxy_buffering on`)
|
||||
- Allows advanced content filtering (e.g., via Lua body/headers)
|
||||
- Suitable for most REST APIs, web frontends, and admin panels
|
||||
|
||||
- **Pros:**
|
||||
- Enables HTML/body manipulation (for injecting snippets, analytics, CSP, etc.)
|
||||
- Optimized for efficient caching and GZIP compression
|
||||
- Good default for "normal" web traffic
|
||||
|
||||
- **Cons:**
|
||||
- **Not** suitable for WebSocket endpoints (buffering can break WS)
|
||||
- Slightly more latency for streaming data due to buffering
|
||||
|
||||
---
|
||||
|
||||
### 2. `ws_generic.conf.j2`
|
||||
**Use this template for applications requiring WebSocket support.**
|
||||
Designed for services (e.g., chat servers, real-time dashboards) needing fast, persistent connections using the WebSocket protocol.
|
||||
|
||||
- **Features:**
|
||||
- WebSocket-aware: `proxy_buffering off`, special upgrade headers
|
||||
- Supports standard HTTP/S traffic alongside WebSockets
|
||||
- Proper handling of connection upgrades and protocol switching
|
||||
|
||||
- **Pros:**
|
||||
- Required for all WebSocket endpoints
|
||||
- Allows instant, low-latency bidirectional traffic
|
||||
- Prevents data loss or connection drops due to proxy buffering
|
||||
|
||||
- **Cons:**
|
||||
- Disables body/content filtering and response manipulation
|
||||
- No buffering means less effective for caching/optimization
|
||||
- Not suitable for scenarios requiring Lua/JS content injection
|
||||
|
||||
---
|
||||
|
||||
## Summary Table
|
||||
|
||||
| Use Case | Template | Buffering | WebSocket? | Can Filter Content? |
|
||||
|--------------------------|---------------------|-----------|------------|--------------------|
|
||||
| Static/Classic Website | `basic.conf.j2` | On | No | Yes |
|
||||
| REST API | `basic.conf.j2` | On | No | Yes |
|
||||
| Real-Time Chat/App | `ws_generic.conf.j2`| Off | Yes | No |
|
||||
| Dashboard w/Live Data | `ws_generic.conf.j2`| Off | Yes | No |
|
||||
| Needs HTML Injection | `basic.conf.j2` | On | No | Yes |
|
||||
|
||||
---
|
||||
|
||||
## Good to Know
|
||||
|
||||
- **Never enable buffering for true WebSocket connections!**
|
||||
Use `proxy_buffering off;` (as in `ws_generic.conf.j2`) or connections may fail.
|
||||
- For most classic web applications, use the **basic template**.
|
||||
- For apps where you want to inject or modify HTML (e.g., analytics scripts), **only the basic template** supports this.
|
||||
|
||||
---
|
||||
|
||||
## Author & Project
|
||||
|
||||
By [Kevin Veen-Birkenbach](https://www.veen.world)
|
||||
Part of the [Infinito.Nexus Project](https://s.infinito.nexus/code)
|
||||
Licensed under the [Infinito.Nexus NonCommercial License](https://s.infinito.nexus/license)
|
61
roles/srv-proxy-core/templates/vhost/basic.conf.j2
Normal file
61
roles/srv-proxy-core/templates/vhost/basic.conf.j2
Normal file
@@ -0,0 +1,61 @@
|
||||
server
|
||||
{
|
||||
server_name {{ domain }};
|
||||
|
||||
{% if applications | get_app_conf(application_id, 'features.oauth2', False) %}
|
||||
{% include 'roles/web-app-oauth2-proxy/templates/endpoint.conf.j2'%}
|
||||
{% endif %}
|
||||
|
||||
{% include 'roles/sys-srv-web-inj-compose/templates/server.conf.j2'%}
|
||||
|
||||
{% if proxy_extra_configuration is defined %}
|
||||
{# Additional Domain Specific Configuration #}
|
||||
{{ proxy_extra_configuration }}
|
||||
{% endif %}
|
||||
|
||||
{% include 'roles/srv-letsencrypt/templates/ssl_header.j2' %}
|
||||
|
||||
{% if applications | get_app_conf(application_id, 'features.oauth2', False) %}
|
||||
{% set acl = applications | get_app_conf(application_id, 'oauth2_proxy.acl', False, {}) %}
|
||||
|
||||
{% if acl.blacklist is defined %}
|
||||
{# 1. Expose everything by default, then protect blacklisted paths #}
|
||||
{% set oauth2_proxy_enabled = false %}
|
||||
{% set location = "/" %}
|
||||
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
|
||||
|
||||
{% for loc in acl.blacklist %}
|
||||
{% set oauth2_proxy_enabled = true %}
|
||||
{% set location = loc %}
|
||||
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
|
||||
{% endfor %}
|
||||
|
||||
{% elif acl.whitelist is defined %}
|
||||
{# 2. Protect everything by default, then expose whitelisted paths #}
|
||||
{% set oauth2_proxy_enabled = true %}
|
||||
{% set location = "/" %}
|
||||
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
|
||||
|
||||
{% for loc in acl.whitelist %}
|
||||
{% set oauth2_proxy_enabled = false %}
|
||||
{% set location = loc %}
|
||||
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
|
||||
{% endfor %}
|
||||
|
||||
{% else %}
|
||||
{# 3. OAuth2 enabled but no (or empty) ACL — protect all #}
|
||||
{% set oauth2_proxy_enabled = true %}
|
||||
{% set location = "/" %}
|
||||
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
{# 4. OAuth2 completely disabled — expose all #}
|
||||
{% set oauth2_proxy_enabled = false %}
|
||||
{% set location = "/" %}
|
||||
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
|
||||
{% endif %}
|
||||
|
||||
}
|
||||
|
||||
|
35
roles/srv-proxy-core/templates/vhost/ws_generic.conf.j2
Normal file
35
roles/srv-proxy-core/templates/vhost/ws_generic.conf.j2
Normal file
@@ -0,0 +1,35 @@
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
server_name {{ domain }};
|
||||
|
||||
{% include 'roles/srv-letsencrypt/templates/ssl_header.j2' %}
|
||||
|
||||
{% include 'roles/sys-srv-web-inj-compose/templates/server.conf.j2' %}
|
||||
|
||||
client_max_body_size {{ client_max_body_size | default('100m') }};
|
||||
keepalive_timeout 70;
|
||||
sendfile on;
|
||||
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_buffers 16 8k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000";
|
||||
|
||||
{% include 'roles/srv-proxy-core/templates/location/html.conf.j2' %}
|
||||
|
||||
{% if location_ws is defined %}
|
||||
{% include 'roles/srv-proxy-core/templates/location/ws.conf.j2' %}
|
||||
{% endif %}
|
||||
|
||||
error_page 500 501 502 503 504 /500.html;
|
||||
}
|
Reference in New Issue
Block a user