Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nginx_proxy: Adding support for TCP Proxy Protocol #3274

Merged
merged 9 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion nginx_proxy/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 3.10.0

- Supporting TCP Proxy Protocol

## 3.9.0

- Add `map_hash_bucket_size` to add support for longer matches in `map`
Expand All @@ -11,7 +15,7 @@
## 3.7.0

- Modify `server_names_hash_bucket_size` to add support for longer domain names

## 3.6.0

- Add port to Host header to fix origin issues affecting ESPHome and other addons
Expand Down
5 changes: 5 additions & 0 deletions nginx_proxy/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ customize:
default: "nginx_proxy_default*.conf"
servers: "nginx_proxy/*.conf"
cloudflare: false
real_ip_from:
```

### Option: `domain` (required)
Expand Down Expand Up @@ -78,6 +79,10 @@ The filename(s) of the NGINX configuration for the additional servers, found in
If enabled, configure Nginx with a list of IP addresses directly from Cloudflare that will be used for `set_real_ip_from` directive Nginx config.
This is so the `ip_ban_enabled` feature can be used and work correctly in /config/customize.yaml.

### Option `real_ip_from` (optional)

If specified, configures Nginx to use Proxy Protocol to get the Real Ip from an upstream load balancer; [for more information](https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/).

## Known issues and limitations

- By default, port 80 is disabled in the add-on configuration in case the port is needed for other components or add-ons like `emulated_hue`.
Expand Down
4 changes: 3 additions & 1 deletion nginx_proxy/config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
version: 3.9.0
version: 3.10.0
hassio_api: true
slug: nginx_proxy
name: NGINX Home Assistant SSL proxy
Expand Down Expand Up @@ -39,3 +39,5 @@ schema:
active: bool
default: str
servers: str
real_ip_from:
- str
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
{{/*
Options saved in the addon UI are available in .options
Some variables are available in .variables, these are added in nginx/run
*/}}
daemon off;
error_log stderr;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
worker_connections 1024;
}

http {
Expand All @@ -17,14 +21,16 @@ http {
server_tokens off;

server_names_hash_bucket_size 128;
# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

#include /data/cloudflare.conf;

{{- if .options.cloudflare }}
include /data/cloudflare.conf;
{{- end }}

server {
server_name _;
listen 80 default_server;
Expand All @@ -34,43 +40,63 @@ http {
}

server {
server_name %%DOMAIN%%;
server_name {{ .options.domain }};

# These shouldn't need to be changed
listen 80;
return 301 https://$host$request_uri;
}

server {
server_name %%DOMAIN%%;
server_name {{ .options.domain }};

ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
ssl_certificate /ssl/%%FULLCHAIN%%;
ssl_certificate_key /ssl/%%PRIVKEY%%;
ssl_certificate /ssl/{{ .options.certfile }};
ssl_certificate_key /ssl/{{ .options.keyfile }};

# dhparams file
ssl_dhparam /data/dhparams.pem;


{{- if not .options.real_ip_from }}
listen 443 ssl http2;
%%HSTS%%
{{- else }}
listen 443 ssl http2 proxy_protocol;
{{- range .options.real_ip_from }}
set_real_ip_from {{.}};
{{- end }}
real_ip_header proxy_protocol;
{{- end }}

{{- if .options.hsts }}
add_header Strict-Transport-Security "{{ .options.hsts }}" always;
{{- end }}

proxy_buffering off;

#include /share/nginx_proxy_default*.conf;

{{- if .options.customize.active }}
include /share/{{ .options.customize.default }};
{{- end }}

location / {
proxy_pass http://homeassistant.local.hass.io:%%HA_PORT%%;
proxy_pass http://homeassistant.local.hass.io:{{ .variables.port }};
proxy_set_header Host $http_host;
proxy_redirect http:// https://;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-Host $http_host;
{{- if not .options.real_ip_from }}
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
{{- else }}
proxy_set_header X-Real-IP $proxy_protocol_addr;
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
{{- end }}
}
}

#include /share/nginx_proxy/*.conf;
{{- if .options.customize.active }}
include /share/{{ .options.customize.servers }};
{{- end }}
}
36 changes: 10 additions & 26 deletions nginx_proxy/rootfs/etc/s6-overlay/s6-rc.d/nginx/run
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,26 @@

set -e

bashio::log.info "Merging options & variables for template"
JSON_CONF=$(jq --arg port $(bashio::core.port) \
'({options: .}) + ({variables: {port: $port}})' \
/data/options.json)
bashio::log.info "Generating nginx.conf from template in /etc/nginx/nginx.conf.gtpl"
echo $JSON_CONF | tempio \
-template /etc/nginx/nginx.conf.gtpl \
-out /etc/nginx.conf

DHPARAMS_PATH=/data/dhparams.pem

CLOUDFLARE_CONF=/data/cloudflare.conf

DOMAIN=$(bashio::config 'domain')
KEYFILE=$(bashio::config 'keyfile')
CERTFILE=$(bashio::config 'certfile')
HSTS=$(bashio::config 'hsts')

HA_PORT=$(bashio::core.port)

# Generate dhparams
if ! bashio::fs.file_exists "${DHPARAMS_PATH}"; then
bashio::log.info "Generating dhparams (this will take some time)..."
openssl dhparam -dsaparam -out "$DHPARAMS_PATH" 4096 > /dev/null
fi

if bashio::config.true 'cloudflare'; then
sed -i "s|#include /data/cloudflare.conf;|include /data/cloudflare.conf;|" /etc/nginx.conf
# Generate cloudflare.conf
if ! bashio::fs.file_exists "${CLOUDFLARE_CONF}"; then
bashio::log.info "Creating 'cloudflare.conf' for real visitor IP address..."
Expand All @@ -47,24 +48,7 @@ if bashio::config.true 'cloudflare'; then
fi
fi

# Prepare config file
sed -i "s#%%FULLCHAIN%%#$CERTFILE#g" /etc/nginx.conf
sed -i "s#%%PRIVKEY%%#$KEYFILE#g" /etc/nginx.conf
sed -i "s/%%DOMAIN%%/$DOMAIN/g" /etc/nginx.conf
sed -i "s/%%HA_PORT%%/$HA_PORT/g" /etc/nginx.conf

[ -n "$HSTS" ] && HSTS="add_header Strict-Transport-Security \"$HSTS\" always;"
sed -i "s/%%HSTS%%/$HSTS/g" /etc/nginx.conf

# Allow customize configs from share
if bashio::config.true 'customize.active'; then
CUSTOMIZE_DEFAULT=$(bashio::config 'customize.default')
sed -i "s|#include /share/nginx_proxy_default.*|include /share/$CUSTOMIZE_DEFAULT;|" /etc/nginx.conf
CUSTOMIZE_SERVERS=$(bashio::config 'customize.servers')
sed -i "s|#include /share/nginx_proxy/.*|include /share/$CUSTOMIZE_SERVERS;|" /etc/nginx.conf
fi

# start server
bashio::log.info "Running nginx..."
stat "/ssl/${CERTFILE}" -c %y > /tmp/certificate_timestamp
stat "/ssl/$(bashio::config 'certfile')" -c %y > /tmp/certificate_timestamp
exec nginx -c /etc/nginx.conf < /dev/null
5 changes: 5 additions & 0 deletions nginx_proxy/translations/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ configuration:
name: Customize
description: >-
See the Documentation tab for more information about these options.
real_ip_from:
name: Real IP from (enables PROXY protocol)
description: >-
Configures Nginx to use TCP Proxy Protocol,
specifies what IP to trust TLS upstream requests from.
network:
443/tcp: HTTPS (SSL) Port
80/tcp: HTTP (non-SSL) Port