Skip to content

Instantly share code, notes, and snippets.

@R0GGER
Last active May 22, 2025 19:00
Show Gist options
  • Save R0GGER/916183fca41f02df1471a6f455e5869f to your computer and use it in GitHub Desktop.
Save R0GGER/916183fca41f02df1471a6f455e5869f to your computer and use it in GitHub Desktop.
Workaround - Security Headers @ NGINX Proxy Manager
{% if certificate and certificate_id > 0 -%}
{% if ssl_forced == 1 or ssl_forced == true %}
{% if hsts_enabled == 1 or hsts_enabled == true %}
# HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
add_header Strict-Transport-Security "max-age=63072000;{% if hsts_subdomains == 1 or hsts_subdomains == true -%} includeSubDomains;{% endif %} preload" always;
add_header Referrer-Policy strict-origin-when-cross-origin;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Frame-Options SAMEORIGIN;
add_header Content-Security-Policy upgrade-insecure-requests;
add_header Permissions-Policy interest-cohort=();
add_header Expect-CT 'enforce; max-age=604800';
more_set_headers 'Server: Proxy';
more_clear_headers 'X-Powered-By';
{% endif %}
{% endif %}
{% endif %}
@R0GGER
Copy link
Author

R0GGER commented Apr 21, 2021

Security Headers for NGINX Proxy Manager

Issue: NginxProxyManager/nginx-proxy-manager#582

Due to a bug it's impossible to add securityheaders to NGINX Proxy Manager.
Use this workaround to fix this issue:

Step 1. Download _hsts.conf
Step 2. Create a volume to this file (read-only)

Docker CLI

Volume location depends on Docker image.

Image: jlesage/nginx-proxy-manager

-v /PROXY-PATH/_hsts.conf:/opt/nginx-proxy-manager/templates/_hsts.conf:ro

Image: jc21/nginx-proxy-manager

-v /PROXY-PATH/_hsts.conf:/app/templates/_hsts.conf:ro

Docker Compose

Volume location depends on Docker image.

Image: jlesage/nginx-proxy-manager

volumes:
    -  /PROXY-PATH/_hsts.conf:/opt/nginx-proxy-manager/templates/_hsts.conf:ro

Image:"jc21/nginx-proxy-manager

volumes:
    -  /PROXY-PATH/_hsts.conf:/app/templates/_hsts.conf:ro

Step 3.
Go to NGINX Proxy Manager, click Edit and go to the tab SSL.
Enable and/or re-enable Force SSL, HSTS Enabled and HSTS Subdomains.
qRU5q9

Done!

Note: If you have enabled an Access List not all headers will load. This is not a bug!

Result @ https://securityheaders.com:

lEqfXZ

@fahadshery
Copy link

Hi,
Screenshot 2021-11-20 at 09 01 40

I am having issue with setting up the Strict-Transport-Security. Here is my _hsts.conf:

{% if certificate and certificate_id > 0 -%}
{% if ssl_forced == 1 or ssl_forced == true %}
{% if hsts_enabled == 1 or hsts_enabled == true %}
  # HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
  add_header Strict-Transport-Security "max-age=15552000;{% if hsts_subdomains == 1 or hsts_subdomains == true -%} includeSubDomains;{% endif %} preload" always;
  add_header Referrer-Policy strict-origin-when-cross-origin;
  add_header X-Content-Type-Options nosniff;
  add_header Content-Security-Policy upgrade-insecure-requests;
  add_header Permissions-Policy interest-cohort=();
  add_header Expect-CT 'enforce; max-age=604800';
  more_set_headers 'Server: Proxy';
  more_clear_headers 'X-Powered-By';
{% endif %}
{% endif %}
{% endif %}

You might notice that referrer-policy and x-content-type-options appear twice in the above image.
What am I missing? any ideas?

@R0GGER
Copy link
Author

R0GGER commented Nov 20, 2021

No not your fault... This happens when the application you're proxying has headers too...

Edit: Ah, you found your answer already. Issue: NginxProxyManager/nginx-proxy-manager#1601

@fahadshery
Copy link

Hi @R0GGER,

thanks for the reply. As I mentioned, it was cloud flare who was adding or replacing my own header values.

@shruuub
Copy link

shruuub commented Jun 19, 2022

Hey,
I know this is pretty old by now, but I was wondering if it is possible to change the Server header. Changed it in the _hsts.conf, but it doesnt change(Have tried restart and recreate). Is it simply not possible, or am I doing something wrong?

@R0GGER
Copy link
Author

R0GGER commented Jun 29, 2022

Hi shruub,

Paths depend on which NGINX Proxy Manager docker image you're using...
Before you add /your host/_hsts.conf:/opt/nginx-proxy-manager/templates/_hsts.conf:ro to your docker-compose file of docker cli , make sure you've saved _hsts.conf on the host.

Once NGINX Proxy Manager is running again, just go to a proxy host, click edit, tab: ssl, click enable HSTS Enabled and HSTS Subdomains and Save.

@shruuub
Copy link

shruuub commented Jun 29, 2022

Hello rogger,
thanks for the fast response, issue is fixed after disabling and re-enabling HSTS and subdomains! :)

@nikkopt
Copy link

nikkopt commented Oct 18, 2022

It doesn't seem to be working for me. I get an F on securityheaders.com . Do i only need to create that file and enable HSTS? I'm trying to fix CORS error on the homer dashboard.
I also added
add_header Access-Control-Allow-Origin *;
but like the other headers, it doesn't work.

Is the _hsts.conf supposed to be next to the _assets.conf dead_host.conf _exploits.conf _header_comment.conf , etc, files?

Edit: I noticed that it somehow works. While using the browser inspector i can see that some files get the headers and some don't

@maximushugus
Copy link

Thanks for sharing your config !
As said on a comment the problem is that if an application already has on of those header, the same header (maybe with a different value) is added by NPM, wich could cause issue and is not following the standards.

So I made so changes :

First here is my _hsts.conf file :

{% if certificate and certificate_id > 0 -%}
{% if ssl_forced == 1 or ssl_forced == true %}
{% if hsts_enabled == 1 or hsts_enabled == true %}
add_header Strict-Transport-Security $hdr_strict_transport_security;
add_header Referrer-Policy $hdr_referrer_policy;
add_header X-Content-Type-Options $hdr_x_content_type_options;
add_header X-XSS-Protection $hdr_x_xss_protection;
add_header X-Frame-Options $hdr_x_frame_options;
add_header Content-Security-Policy $hdr_content_security_policy;
add_header Permissions-Policy $hdr_permissions_policy;
add_header Expect-CT $hdr_expect_ct;
more_set_headers 'Server: Proxy';
more_clear_headers 'X-Powered-By';
{% endif %}
{% endif %}
{% endif %}

Then I created (or modified) in /data/nginx/custom a http_top.conf file :

map $upstream_http_strict_transport_security $hdr_strict_transport_security {
'' "max-age=63072000; includeSubDomains; preload";
}

map $upstream_http_referrer_policy $hdr_referrer_policy {
'' "strict-origin-when-cross-origin";
}

map $upstream_http_x_content_type_options $hdr_x_content_type_options {
'' "nosniff";
}

map $upstream_http_x_xss_protection $hdr_x_xss_protection {
'' "1; mode=block";
}

map $upstream_http_x_frame_options $hdr_x_frame_options {
'' "SAMEORIGIN";
}

map $upstream_http_content_security_policy $hdr_content_security_policy {
'' "upgrade-insecure-requests";
}

map $upstream_http_permissions_policy $hdr_permissions_policy {
'' "interest-cohort=()";
}

map $upstream_http_expect_ct $hdr_expect_ct {
'' "enforce, max-age=604800";
}

Than restarting nginx and disabling SSL and saving in NPM, and enabling it again.
With this configuration nginx only adds those header if they are not already send by the underling application.

The only thing is if you want to disable on of those header (X-frame for me) on a specified application, you have to put the entire configuration for this application in the advanced tap with "location/{ ....}

@jce-zz
Copy link

jce-zz commented May 7, 2024

@maximushugus Thanks for sharing your config and updates! Works like a charm! :-)

@DKT69
Copy link

DKT69 commented May 21, 2025

may i ask this compatible with npmplus?

@DKT69
Copy link

DKT69 commented May 21, 2025

i using on npmplus only get "B", any latest update for this?

Security Headers for NGINX Proxy Manager

Issue: NginxProxyManager/nginx-proxy-manager#582

Due to a bug it's impossible to add securityheaders to NGINX Proxy Manager. Use this workaround to fix this issue:

Step 1. Download _hsts.conf Step 2. Create a volume to this file (read-only)

Docker CLI

Volume location depends on Docker image.

Image: jlesage/nginx-proxy-manager

-v /PROXY-PATH/_hsts.conf:/opt/nginx-proxy-manager/templates/_hsts.conf:ro

Image: jc21/nginx-proxy-manager

-v /PROXY-PATH/_hsts.conf:/app/templates/_hsts.conf:ro

Docker Compose

Volume location depends on Docker image.

Image: jlesage/nginx-proxy-manager

volumes:
    -  /PROXY-PATH/_hsts.conf:/opt/nginx-proxy-manager/templates/_hsts.conf:ro

Image:"jc21/nginx-proxy-manager

volumes:
    -  /PROXY-PATH/_hsts.conf:/app/templates/_hsts.conf:ro

Step 3. Go to NGINX Proxy Manager, click Edit and go to the tab SSL. Enable and/or re-enable Force SSL, HSTS Enabled and HSTS Subdomains. qRU5q9

Done!

Note: If you have enabled an Access List not all headers will load. This is not a bug!

Result @ https://securityheaders.com:

lEqfXZ


Hi, i using on npmplus only get "B" with Cloudflare Proxied, any latest update for this?

image

@R0GGER
Copy link
Author

R0GGER commented May 21, 2025

I think... I am not using npmplus, but anyway try this:

Add to hsts.conf

add_header Content-Security-Policy $hdr_content_security_policy;
add_header Permissions-Policy $hdr_permissions_policy;

Copy/paste in hsts.conf -> nano /opt/npmplus/hsts.conf

more_clear_headers "Expect-CT";
more_clear_headers "Public-Key-Pins";
more_set_headers "X-XSS-Protection: 0";

more_set_headers "X-Content-Type-Options: nosniff";
more_set_headers "X-Frame-Options: SAMEORIGIN"; # or what ever you set using env
more_set_headers "Content-Security-Policy: $content_security_policy"; # if not set by upstream: upgrade-insecure-requests, else upstreams value is used

more_set_headers "Strict-Transport-Security: $hsts_header"; # means: max-age=63072000; includeSubDomains; preload (includeSubDomains not if disabled via env)

add_header Content-Security-Policy $hdr_content_security_policy;
add_header Permissions-Policy $hdr_permissions_policy;

Add to compose.yaml

      - /opt/npmplus/hsts.conf:/usr/local/nginx/conf/conf.d/include/hsts.conf:ro

And restart npmplus....

@DKT69
Copy link

DKT69 commented May 22, 2025

I think... I am not using npmplus, but anyway try this:

Add to hsts.conf

add_header Content-Security-Policy $hdr_content_security_policy;
add_header Permissions-Policy $hdr_permissions_policy;

Copy/paste in hsts.conf -> nano /opt/npmplus/hsts.conf

more_clear_headers "Expect-CT";
more_clear_headers "Public-Key-Pins";
more_set_headers "X-XSS-Protection: 0";

more_set_headers "X-Content-Type-Options: nosniff";
more_set_headers "X-Frame-Options: SAMEORIGIN"; # or what ever you set using env
more_set_headers "Content-Security-Policy: $content_security_policy"; # if not set by upstream: upgrade-insecure-requests, else upstreams value is used

more_set_headers "Strict-Transport-Security: $hsts_header"; # means: max-age=63072000; includeSubDomains; preload (includeSubDomains not if disabled via env)

add_header Content-Security-Policy $hdr_content_security_policy;
add_header Permissions-Policy $hdr_permissions_policy;

Add to compose.yaml

      - /opt/npmplus/hsts.conf:/usr/local/nginx/conf/conf.d/include/hsts.conf:ro

And restart npmplus....


i getting error

nginx: [emerg] invalid number of arguments in "add_header" directive in /usr/local/nginx/conf/conf.d/include/hsts.conf:11

@R0GGER
Copy link
Author

R0GGER commented May 22, 2025

Have you tried to change add_header to more_set_headers?

add_header Content-Security-Policy $hdr_content_security_policy;
add_header Permissions-Policy $hdr_permissions_policy;
more_set_headers "Content-Security-Policy $hdr_content_security_policy";
more_set_headers "Permissions-Policy $hdr_permissions_policy";

@DKT69
Copy link

DKT69 commented May 22, 2025

yes tried. it error too.

nginx: [emerg] unknown "hdr_content_security_policy" variable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment