From 83e9ae616ae0f5a0de44bf97528ce2ab0b876bdc Mon Sep 17 00:00:00 2001 From: scyto Date: Mon, 18 Aug 2025 16:39:12 -0700 Subject: [PATCH] Enable Optional IPv6 Support for Nginx (#19602) --- .../etc/s6-overlay/s6-rc.d/certsync/run | 2 +- .../rootfs/etc/s6-overlay/s6-rc.d/nginx/run | 2 +- ...tls_settings.py => get_listen_settings.py} | 8 ++- .../usr/local/nginx/templates/listen.gotmpl | 66 +++++++++++-------- docs/docs/configuration/reference.md | 6 ++ frigate/config/config.py | 4 ++ frigate/config/network.py | 13 ++++ 7 files changed, 70 insertions(+), 31 deletions(-) rename docker/main/rootfs/usr/local/nginx/{get_tls_settings.py => get_listen_settings.py} (71%) create mode 100644 frigate/config/network.py diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run index af3bc04de..5b8291665 100755 --- a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/certsync/run @@ -10,7 +10,7 @@ echo "[INFO] Starting certsync..." lefile="/etc/letsencrypt/live/frigate/fullchain.pem" -tls_enabled=`python3 /usr/local/nginx/get_tls_settings.py | jq -r .enabled` +tls_enabled=`python3 /usr/local/nginx/get_listen_settings.py | jq -r .enabled` while true do diff --git a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run index 273182930..8bd9b5250 100755 --- a/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run +++ b/docker/main/rootfs/etc/s6-overlay/s6-rc.d/nginx/run @@ -85,7 +85,7 @@ python3 /usr/local/nginx/get_base_path.py | \ -out /usr/local/nginx/conf/base_path.conf # build templates for optional TLS support -python3 /usr/local/nginx/get_tls_settings.py | \ +python3 /usr/local/nginx/get_listen_settings.py | \ tempio -template /usr/local/nginx/templates/listen.gotmpl \ -out /usr/local/nginx/conf/listen.conf diff --git a/docker/main/rootfs/usr/local/nginx/get_tls_settings.py b/docker/main/rootfs/usr/local/nginx/get_listen_settings.py similarity index 71% rename from docker/main/rootfs/usr/local/nginx/get_tls_settings.py rename to docker/main/rootfs/usr/local/nginx/get_listen_settings.py index d2e704056..d879db56e 100644 --- a/docker/main/rootfs/usr/local/nginx/get_tls_settings.py +++ b/docker/main/rootfs/usr/local/nginx/get_listen_settings.py @@ -26,6 +26,10 @@ try: except FileNotFoundError: config: dict[str, Any] = {} -tls_config: dict[str, Any] = config.get("tls", {"enabled": True}) +tls_config: dict[str, any] = config.get("tls", {"enabled": True}) +networking_config = config.get("networking", {}) +ipv6_config = networking_config.get("ipv6", {"enabled": False}) -print(json.dumps(tls_config)) +output = {"tls": tls_config, "ipv6": ipv6_config} + +print(json.dumps(output)) diff --git a/docker/main/rootfs/usr/local/nginx/templates/listen.gotmpl b/docker/main/rootfs/usr/local/nginx/templates/listen.gotmpl index 093d5f68e..066f872cb 100644 --- a/docker/main/rootfs/usr/local/nginx/templates/listen.gotmpl +++ b/docker/main/rootfs/usr/local/nginx/templates/listen.gotmpl @@ -1,33 +1,45 @@ -# intended for internal traffic, not protected by auth + +# Internal (IPv4 always; IPv6 optional) listen 5000; +{{ if .ipv6 }}{{ if .ipv6.enabled }}listen [::]:5000;{{ end }}{{ end }} + -{{ if not .enabled }} # intended for external traffic, protected by auth -listen 8971; +{{ if .tls }} + {{ if .tls.enabled }} + # external HTTPS (IPv4 always; IPv6 optional) + listen 8971 ssl; + {{ if .ipv6 }}{{ if .ipv6.enabled }}listen [::]:8971 ssl;{{ end }}{{ end }} + + ssl_certificate /etc/letsencrypt/live/frigate/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/frigate/privkey.pem; + + # generated 2024-06-01, Mozilla Guideline v5.7, nginx 1.25.3, OpenSSL 1.1.1w, modern configuration, no OCSP + # https://ssl-config.mozilla.org/#server=nginx&version=1.25.3&config=modern&openssl=1.1.1w&ocsp=false&guideline=5.7 + ssl_session_timeout 1d; + ssl_session_cache shared:MozSSL:10m; # about 40000 sessions + ssl_session_tickets off; + + # modern configuration + ssl_protocols TLSv1.3; + ssl_prefer_server_ciphers off; + + # HSTS (ngx_http_headers_module is required) (63072000 seconds) + add_header Strict-Transport-Security "max-age=63072000" always; + + # ACME challenge location + location /.well-known/acme-challenge/ { + default_type "text/plain"; + root /etc/letsencrypt/www; + } + {{ else }} + # external HTTP (IPv4 always; IPv6 optional) + listen 8971; + {{ if .ipv6 }}{{ if .ipv6.enabled }}listen [::]:8971;{{ end }}{{ end }} + {{ end }} {{ else }} -# intended for external traffic, protected by auth -listen 8971 ssl; - -ssl_certificate /etc/letsencrypt/live/frigate/fullchain.pem; -ssl_certificate_key /etc/letsencrypt/live/frigate/privkey.pem; - -# generated 2024-06-01, Mozilla Guideline v5.7, nginx 1.25.3, OpenSSL 1.1.1w, modern configuration, no OCSP -# https://ssl-config.mozilla.org/#server=nginx&version=1.25.3&config=modern&openssl=1.1.1w&ocsp=false&guideline=5.7 -ssl_session_timeout 1d; -ssl_session_cache shared:MozSSL:10m; # about 40000 sessions -ssl_session_tickets off; - -# modern configuration -ssl_protocols TLSv1.3; -ssl_prefer_server_ciphers off; - -# HSTS (ngx_http_headers_module is required) (63072000 seconds) -add_header Strict-Transport-Security "max-age=63072000" always; - -# ACME challenge location -location /.well-known/acme-challenge/ { - default_type "text/plain"; - root /etc/letsencrypt/www; -} + # (No tls section) default to HTTP (IPv4 always; IPv6 optional) + listen 8971; + {{ if .ipv6 }}{{ if .ipv6.enabled }}listen [::]:8971;{{ end }}{{ end }} {{ end }} diff --git a/docs/docs/configuration/reference.md b/docs/docs/configuration/reference.md index e54f07a2b..c4c024853 100644 --- a/docs/docs/configuration/reference.md +++ b/docs/docs/configuration/reference.md @@ -73,6 +73,12 @@ tls: # Optional: Enable TLS for port 8971 (default: shown below) enabled: True +# Optional: IPv6 configuration +networking: + # Optional: Enable IPv6 on 5000, and 8971 if tls is configured (default: shown below) + ipv6: + enabled: False + # Optional: Proxy configuration proxy: # Optional: Mapping for headers from upstream proxies. Only used if Frigate's auth diff --git a/frigate/config/config.py b/frigate/config/config.py index de41c1d24..dd84639d3 100644 --- a/frigate/config/config.py +++ b/frigate/config/config.py @@ -64,6 +64,7 @@ from .database import DatabaseConfig from .env import EnvVars from .logger import LoggerConfig from .mqtt import MqttConfig +from .network import NetworkingConfig from .proxy import ProxyConfig from .telemetry import TelemetryConfig from .tls import TlsConfig @@ -334,6 +335,9 @@ class FrigateConfig(FrigateBaseModel): notifications: NotificationConfig = Field( default_factory=NotificationConfig, title="Global notification configuration." ) + networking: NetworkingConfig = Field( + default_factory=NetworkingConfig, title="Networking configuration" + ) proxy: ProxyConfig = Field( default_factory=ProxyConfig, title="Proxy configuration." ) diff --git a/frigate/config/network.py b/frigate/config/network.py new file mode 100644 index 000000000..c8b3cfd1c --- /dev/null +++ b/frigate/config/network.py @@ -0,0 +1,13 @@ +from pydantic import Field + +from .base import FrigateBaseModel + +__all__ = ["IPv6Config", "NetworkingConfig"] + + +class IPv6Config(FrigateBaseModel): + enabled: bool = Field(default=False, title="Enable IPv6 for port 5000 and/or 8971") + + +class NetworkingConfig(FrigateBaseModel): + ipv6: IPv6Config = Field(default_factory=IPv6Config, title="Network configuration")