mirror of
https://github.com/dokku/dokku.git
synced 2025-12-29 00:25:08 +01:00
Merge pull request #4340 from bjornpost/feature/4339-respect-fwded-for-header
Allow configuring x-forwarded-* proxy headers via nginx:set
This commit is contained in:
@@ -136,35 +136,12 @@ Certain versions of nginx have bugs that prevent [HTTP/2](https://nginx.org/en/d
|
||||
|
||||
Your application has access to the HTTP headers `X-Forwarded-Proto`, `X-Forwarded-Port` and `X-Forwarded-For`. These headers indicate the protocol of the original request (HTTP or HTTPS), the port number, and the IP address of the client making the request, respectively. The default configuration is for Nginx to set these headers.
|
||||
|
||||
If your server runs behind an HTTP(S) load balancer, then Nginx will see all requests as coming from the load balancer. If your load balancer sets the `X-Forwarded-` headers, you can tell Nginx to pass these headers from load balancer to your application by using a [custom nginx template](/docs/configuration/nginx.md#customizing-the-nginx-configuration). The following is a simple example of how to do so.
|
||||
If your server runs behind an HTTP(S) load balancer, then Nginx will see all requests as coming from the load balancer. If your load balancer sets the `X-Forwarded-` headers, you can tell Nginx to pass these headers from load balancer to your application via `nginx:set`:
|
||||
|
||||
```go
|
||||
server {
|
||||
listen [::]:{{ .PROXY_PORT }};
|
||||
listen {{ .PROXY_PORT }};
|
||||
server_name {{ .NOSSL_SERVER_NAME }};
|
||||
access_log /var/log/nginx/{{ .APP }}-access.log;
|
||||
error_log /var/log/nginx/{{ .APP }}-error.log;
|
||||
|
||||
location / {
|
||||
proxy_pass http://{{ .APP }};
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
|
||||
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Port $http_x_forwarded_port;
|
||||
proxy_set_header X-Request-Start $msec;
|
||||
}
|
||||
include {{ .DOKKU_ROOT }}/{{ .APP }}/nginx.conf.d/*.conf;
|
||||
}
|
||||
|
||||
upstream {{ .APP }} {
|
||||
{{ range .DOKKU_APP_WEB_LISTENERS | split " " }}
|
||||
server {{ . }};
|
||||
{{ end }}
|
||||
}
|
||||
```shell
|
||||
dokku nginx:set node-js-app x-forwarded-for-value "\$http_x_forwarded_for"
|
||||
dokku nginx:set node-js-app x-forwarded-port-value "\$http_x_forwarded_port"
|
||||
dokku nginx:set node-js-app x-forwarded-proto-value "\$http_x_forwarded_proto"
|
||||
```
|
||||
|
||||
Only use this option if:
|
||||
@@ -173,8 +150,6 @@ Only use this option if:
|
||||
|
||||
If it's possible to make HTTP(S) requests directly to Nginx, bypassing the load balancer, or if the load balancer is not configured to set these headers, then it becomes possible for a client to set these headers to arbitrary values.
|
||||
|
||||
This could result in security issue, for example, if your application looks at the value of the `X-Forwarded-Proto` to determine if the request was made over HTTPS.
|
||||
|
||||
### SSL Port Exposure
|
||||
|
||||
When your app is served from port `80` then the `/home/dokku/APP/nginx.conf` file will automatically be updated to instruct nginx to respond to ssl on port 443 as a new cert is added. If your app uses a non-standard port (perhaps you have a dockerfile deploy exposing port `99999`) you may need to manually expose an ssl port via `dokku proxy:ports-add <APP> https:443:99999`.
|
||||
|
||||
@@ -54,6 +54,9 @@ cmd-nginx-report-single() {
|
||||
"--nginx-proxy-busy-buffers-size: $(fn-nginx-proxy-busy-buffers-size "$APP")"
|
||||
"--nginx-proxy-read-timeout: $(fn-nginx-proxy-read-timeout "$APP")"
|
||||
"--nginx-last-visited-at: $(fn-nginx-vhosts-last-visited-at "$APP")"
|
||||
"--nginx-x-forwarded-for-value: $(fn-plugin-property-get-default "nginx" "$APP" "x-forwarded-for-value" "\$remote_addr")"
|
||||
"--nginx-x-forwarded-port-value: $(fn-plugin-property-get-default "nginx" "$APP" "x-forwarded-port-value" "\$server_port")"
|
||||
"--nginx-x-forwarded-proto-value: $(fn-plugin-property-get-default "nginx" "$APP" "x-forwarded-proto-value" "\$scheme")"
|
||||
)
|
||||
|
||||
if [[ -z "$INFO_FLAG" ]]; then
|
||||
|
||||
@@ -462,6 +462,10 @@ nginx_build_config() {
|
||||
local NGINX_BIND_ADDRESS_IP6="$(fn-plugin-property-get-default "nginx" "$APP" "bind-address-ipv6" "::")"
|
||||
[[ -z "$NGINX_BIND_ADDRESS_IP6" ]] && NGINX_BIND_ADDRESS_IP6="::"
|
||||
|
||||
local PROXY_X_FORWARDED_FOR="$(fn-plugin-property-get-default "nginx" "$APP" "x-forwarded-for-value" "\$remote_addr")"
|
||||
local PROXY_X_FORWARDED_PORT="$(fn-plugin-property-get-default "nginx" "$APP" "x-forwarded-port-value" "\$server_port")"
|
||||
local PROXY_X_FORWARDED_PROTO="$(fn-plugin-property-get-default "nginx" "$APP" "x-forwarded-proto-value" "\$scheme")"
|
||||
|
||||
eval "$(config_export app "$APP")"
|
||||
local SIGIL_PARAMS=(-f "$NGINX_TEMPLATE" APP="$APP" DOKKU_ROOT="$DOKKU_ROOT"
|
||||
NOSSL_SERVER_NAME="$NOSSL_SERVER_NAME"
|
||||
@@ -490,7 +494,10 @@ nginx_build_config() {
|
||||
# Deprecated: Remove this after a few versions
|
||||
NGINX_PORT="$PROXY_PORT" NGINX_SSL_PORT="$PROXY_SSL_PORT"
|
||||
PROXY_PORT="$PROXY_PORT" PROXY_SSL_PORT="$PROXY_SSL_PORT" RAW_TCP_PORTS="$RAW_TCP_PORTS"
|
||||
PROXY_PORT_MAP="$PROXY_PORT_MAP" PROXY_UPSTREAM_PORTS="$PROXY_UPSTREAM_PORTS")
|
||||
PROXY_PORT_MAP="$PROXY_PORT_MAP" PROXY_UPSTREAM_PORTS="$PROXY_UPSTREAM_PORTS"
|
||||
PROXY_X_FORWARDED_FOR="$PROXY_X_FORWARDED_FOR"
|
||||
PROXY_X_FORWARDED_PORT="$PROXY_X_FORWARDED_PORT"
|
||||
PROXY_X_FORWARDED_PROTO="$PROXY_X_FORWARDED_PROTO")
|
||||
|
||||
local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE"
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
|
||||
@@ -9,13 +9,13 @@ cmd-nginx-set() {
|
||||
declare cmd="nginx:set"
|
||||
[[ "$1" == "$cmd" ]] && shift 1
|
||||
declare APP="$1" KEY="$2" VALUE="$3"
|
||||
local VALID_KEYS=("access-log-format" "access-log-path" "bind-address-ipv4" "bind-address-ipv6" "disable-custom-config" "error-log-path" "hsts" "hsts-include-subdomains" "hsts-preload" "hsts-max-age" "proxy-read-timeout" "proxy-buffer-size" "proxy-buffering" "proxy-buffers" "proxy-busy-buffers-size")
|
||||
local VALID_KEYS=("access-log-format" "access-log-path" "bind-address-ipv4" "bind-address-ipv6" "disable-custom-config" "error-log-path" "hsts" "hsts-include-subdomains" "hsts-preload" "hsts-max-age" "proxy-read-timeout" "proxy-buffer-size" "proxy-buffering" "proxy-buffers" "proxy-busy-buffers-size" "x-forwarded-for-value" "x-forwarded-port-value" "x-forwarded-proto-value")
|
||||
verify_app_name "$APP"
|
||||
|
||||
[[ -z "$KEY" ]] && dokku_log_fail "No key specified"
|
||||
|
||||
if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then
|
||||
dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, bind-address-ipv4, bind-address-ipv6, disable-custom-config, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, proxy-read-timeout, proxy-buffer-size, proxy-buffering, proxy-buffers, proxy-busy-buffers-size"
|
||||
dokku_log_fail "Invalid key specified, valid keys include: access-log-format, access-log-path, bind-address-ipv4, bind-address-ipv6, disable-custom-config, error-log-path, hsts, hsts-include-subdomains, hsts-preload, hsts-max-age, proxy-read-timeout, proxy-buffer-size, proxy-buffering, proxy-buffers, proxy-busy-buffers-size, x-forwarded-for-value, x-forwarded-port-value, x-forwarded-proto-value"
|
||||
fi
|
||||
|
||||
if [[ -n "$VALUE" ]]; then
|
||||
|
||||
@@ -33,9 +33,9 @@ server {
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_set_header X-Forwarded-For {{ $.PROXY_X_FORWARDED_FOR }};
|
||||
proxy_set_header X-Forwarded-Port {{ $.PROXY_X_FORWARDED_PORT }};
|
||||
proxy_set_header X-Forwarded-Proto {{ $.PROXY_X_FORWARDED_PROTO }};
|
||||
proxy_set_header X-Request-Start $msec;
|
||||
}
|
||||
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
|
||||
@@ -96,9 +96,9 @@ server {
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_set_header X-Forwarded-For {{ $.PROXY_X_FORWARDED_FOR }};
|
||||
proxy_set_header X-Forwarded-Port {{ $.PROXY_X_FORWARDED_PORT }};
|
||||
proxy_set_header X-Forwarded-Proto {{ $.PROXY_X_FORWARDED_PROTO }};
|
||||
proxy_set_header X-Request-Start $msec;
|
||||
}
|
||||
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
|
||||
|
||||
@@ -156,6 +156,102 @@ teardown() {
|
||||
assert_output_contains "127.0.0.1:80;" 0
|
||||
}
|
||||
|
||||
@test "(nginx-vhosts) nginx:set x-forwarded-for-value" {
|
||||
run deploy_app
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:build-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output_contains "X-Forwarded-For \$remote_addr;"
|
||||
|
||||
run /bin/bash -c "dokku nginx:set $TEST_APP x-forwarded-for-value '\$http_x_forwarded_for'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:build-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output_contains "X-Forwarded-For \$http_x_forwarded_for;"
|
||||
}
|
||||
|
||||
@test "(nginx-vhosts) nginx:set x-forwarded-port-value" {
|
||||
run deploy_app
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:build-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output_contains "X-Forwarded-Port \$server_port;"
|
||||
|
||||
run /bin/bash -c "dokku nginx:set $TEST_APP x-forwarded-port-value '\$http_x_forwarded_port'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:build-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output_contains "X-Forwarded-Port \$http_x_forwarded_port;"
|
||||
}
|
||||
|
||||
@test "(nginx-vhosts) nginx:set x-forwarded-proto-value" {
|
||||
run deploy_app
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:build-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output_contains "X-Forwarded-Proto \$scheme;"
|
||||
|
||||
run /bin/bash -c "dokku nginx:set $TEST_APP x-forwarded-proto-value '\$http_x_forwarded_proto'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:build-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output_contains "X-Forwarded-Proto \$http_x_forwarded_proto;"
|
||||
}
|
||||
|
||||
@test "(nginx-vhosts) nginx:validate-config" {
|
||||
deploy_app
|
||||
run /bin/bash -c "dokku nginx:validate-config"
|
||||
|
||||
Reference in New Issue
Block a user