Renamed webserver roles to more speakable names

This commit is contained in:
2025-08-20 08:54:17 +02:00
parent 9cfb8f3a60
commit a4f39ac732
101 changed files with 147 additions and 147 deletions

View 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 **Lets 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)

View 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)

View 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/"

View 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

View File

@@ -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

View 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.

View 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.

View 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 %}
}

View 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;
}

View 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;
}

View 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;
}

View 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)

View 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 %}
}

View 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;
}