Nginx: Difference between revisions

From DWIKI
Tony (talk | contribs)
Tony (talk | contribs)
 
(49 intermediate revisions by the same user not shown)
Line 4: Line 4:
*[http://nginx.org/ Homepage]
*[http://nginx.org/ Homepage]
*[https://deliciousbrains.com/page-caching-varnish-vs-nginx-fastcgi-cache/ Varnish vs nginx]
*[https://deliciousbrains.com/page-caching-varnish-vs-nginx-fastcgi-cache/ Varnish vs nginx]
==Documentation==
*[https://www.nginx.com/resources/wiki/start/ Getting started]
==Nginx and php-fpm==
*[https://www.digitalocean.com/community/tutorials/how-to-host-multiple-websites-securely-with-nginx-and-php-fpm-on-ubuntu-14-04 How To Host Multiple Websites Securely With Nginx And Php-fpm On Ubuntu 14.04]
===Monitoring php-fpm under nginx===
Create /etc/nginx/site-enabled/fpmstatus
server {
        listen 89;
        listen [::]:89;
        server_name localhost;
        location = /fpm-status {
                access_log off;
                allow 127.0.0.1;
                deny all;
                fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
                include fastcgi_params;
                fastcgi_pass unix:/run/php/php-fpm.sock;
                # fastcgi_pass 127.0.0.1:9001;
        }
        location = /fpm-ping {
                access_log off;
                allow 127.0.0.1;
                deny all;
                fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
                include fastcgi_params;
                fastcgi_pass unix:/run/php/php-fpm.sock;
        }
}
TODO find out why monitoring via tcp socket 127.0.0.1:9001 doesn't work


=Notes=
=Notes=
Line 26: Line 61:


=HOWTO=
=HOWTO=
==SSL configuration==
*[https://nginx.org/en/docs/http/configuring_https_servers.html onfiguring HTTPS servers]
*[https://wiki.mozilla.org/Security/Server_Side_TLS Security/Server Side TLS] Mozilla: Security/Server Side TLS]
*[https://ssl-config.mozilla.org/ Mozilla SSL config generator] outdated?
In case of letsencrypt check /etc/letsencrypt/options-ssl-nginx.conf
===Cipher order===
ssl_prefer_server_ciphers on;
==Set server directives globally==
Put them in '''/etc/nginx/conf.d/directives.conf'''
===CSP===
Content Security Policy
*[https://content-security-policy.com/examples/nginx/ Content Security Policy (CSP)
Examples ]
====CSP config example====
add_header Content-Security-Policy "
            default-src 'self';
            frame-src 'none';
            script-src 'self';
            frame-ancestors 'self';
            img-src 'self' data:;
            manifest-src 'self';
            media-src 'self';
            object-src 'self';
            base-uri: 'self';
            form-action: 'self';
            worker-src 'self';" always;
==Client certificates==
===Create client certificate===
openssl pkcs12 -export -inkey ./sample.key -in ./sample.crt -out ./sample.p12
====Add client certificate to chromium====
Add the .p12 in Advanced->Manage certificates->Your certificates
==Logging==
===Log level===
Doesn't seem to be documented, defaults to log all?
===Ignore IP addresses in logs===
Create '''/etc/nginx/conf.d/logignore.conf''' or put in your vhost config:
map $remote_addr $loggable {
    "1.2.3.4" 0;
    # allow rest
    default 1;
}
and then in your vhost configuration:
access_log /var/log/nginx/myhost.access.log combined if=$loggable;
===Regular expression on $request===
To filter out the nextcloud preview 404s:
map $request $loggable {
  "~^GET \/index\.php\/core\/preview.*$" 0;
  default 1;
}
==Get configuration items==
==Get configuration items==
  getconf PAGESIZE
  getconf PAGESIZE


==Redirecting in nginx==
https://www.liquidweb.com/kb/redirecting-urls-using-nginx/
==enable ipv6==
In server section add
listen [::]:443;


==Configure buffer sizes==
==Configure buffer sizes==
See https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size
See https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size
==Dump nginx configuration==
nginx -T
==Rate limiting==
*[https://www.nginx.com/blog/rate-limiting-nginx/ NGINX Rate limiting]
==Limit access==
https://docs.hypernode.com/hypernode-platform/nginx/how-to-block-allow-ip-addresses-in-nginx.html
==nginx and OCSP (stapling) ==
To make sure everything works have *all* certificates in bundle.pem
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/pki/tls/certs/bundle.pem
ssl_certificate /etc/pki/tls/certs/bundle.pem;
ssl_certificate_key /etc/pki/tls/private/mydomain.key;
===Letsencrypt and stapling===
Will be discontinued: https://kbeezie.com/nginx-ssl_stapling-ignored-ocsp-letsencrypt/
==Exclude not found from log==
log_not_found off;
==Allow zabbix to read nginx error log==
setfacl -m g:zabbix:r /var/log/nginx/error.log
(perhaps put this in logrotate postrotate)


=FAQ=
=FAQ=
==php not executed but downloaded==
In case of php-fpm see:
*https://oneuptime.com/blog/post/2025-12-16-nginx-php-download-instead-of-execute/view
==Security settings==
===X-Content-Type-Options===
# ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
add_header X-Content-Type-Options nosniff always;
===Content-Security-Policy (CSP)===
===security.txt===
*[https://www.rfc-editor.org/rfc/rfc9116 RFC 9116]


==Redirecting in nginx==
*https://securitytxt.org/
https://www.liquidweb.com/kb/redirecting-urls-using-nginx/
 
==nginx serving wrong page==
Forgot to tell it to listen on ipv6?
Like
listen [::]:443 ssl;l


==Conflicting server name XXX on 0.0.0.0:80==


==enable ipv6==
==FastCGI sent in stderr: "Primary script unknown" ==
In server section add
Usually means the php script just isn't there
listen [::]:443;


==Error messages==
==Error messages==
===ERR_HTTP2_PROTOCOL_ERROR===
Check with curl:
curl --http2 https://example.com
I got
curl: (92) : frame type: 1, stream: 1, Invalid HTTP header field was receivedname: [content-security-policy]
found out the hard way that add_header arguments have to be on single line
===nginx: [emerg] unknown log format===
Define log_format in '''http''' section before the includes.
=== upstream prematurely closed connection while reading upstream ===
Maybe trying to fetch a large file, like jpg?
=== client intended to send too large body ===
server {
  # default 1m
  client_max_body_size 4m;
===no live upstreams while connecting to upstream===
===no live upstreams while connecting to upstream===
can't connect to whatever backend?
can't connect to whatever backend?
Line 51: Line 230:
*[https://techglimpse.com/upstream-sent-too-big-header-while-reading-response-header-from-upstream-nginx/ Upstream sent too big header]
*[https://techglimpse.com/upstream-sent-too-big-header-while-reading-response-header-from-upstream-nginx/ Upstream sent too big header]
*[https://www.getpagespeed.com/server-setup/nginx/tuning-proxy_buffer_size-in-nginx Tuning proxy_buffer_size in NGINX]
*[https://www.getpagespeed.com/server-setup/nginx/tuning-proxy_buffer_size-in-nginx Tuning proxy_buffer_size in NGINX]
====In case of fastcgi====
https://gist.github.com/magnetikonline/11312172#determine-fastcgi-response-sizes
Try settings like
fastcgi_buffers 32 32k;
fastcgi_buffer_size 32k;
===an upstream response is buffered to a temporary file===


===(SSL: error:141CF06C:SSL routines:tls_parse_ctos_key_share:bad key share) while SSL handshaking===
===(SSL: error:141CF06C:SSL routines:tls_parse_ctos_key_share:bad key share) while SSL handshaking===
Usually just a bad client or a scan.
Usually just a bad client or a scan.


===cannot load certificate "/etc/ssl/certs/ssl-cert-snakeoil.pem===
Probably ubuntu?
apt install ssl-cert


===access forbidden by rule===
===access forbidden by rule===
Line 60: Line 252:


===a client request body is buffered to a temporary file===
===a client request body is buffered to a temporary file===
Check '''client_body_buffer_size'''?
PLay some with
Or just the other buffer sizes
client_body_buffer_size 10M;
client_max_body_size 10M;
 
TODO check, this doesn't seem to apply
If all else fails just set:
    proxy_max_temp_file_size 0;
and see if you get some feedback :)
 
===upstream timed out===
Look for proxy_pass
 
 
===failed (104: Unknown error) while reading response header from upstream===
 
===[emerg] duplicate listen options for [::]:443 ===
looks like "ipv6only=on" added by letsencrypt causes that, removing it might help
 
===nginx: [emerg] a duplicate default server for 0.0.0.0:80===
Multiple vhosts having "default_server" in their '''listen''' lines


==Logging==


===Log level===
===nginx: [error] invalid PID number "" in "/run/nginx.pid"===
Doesn't seem to be documented, defaults to log all?
Try
systemctl restart nginx
 
===upstream sent no valid HTTP/1.0 ===
Check for confusion between http and https


[[Category: Proxy]]
[[Category: Proxy]]
[[Category: Web Services]]

Latest revision as of 08:30, 4 June 2026

HTTP server, proxy, reverse proxy etc

Links

Documentation

Nginx and php-fpm

Monitoring php-fpm under nginx

Create /etc/nginx/site-enabled/fpmstatus

server {
       listen 89;
       listen [::]:89;
       server_name localhost;
       location = /fpm-status {
               access_log off;
               allow 127.0.0.1;
               deny all;
               fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
               include fastcgi_params;
               fastcgi_pass unix:/run/php/php-fpm.sock;
               # fastcgi_pass 127.0.0.1:9001;
       }
       location = /fpm-ping {
               access_log off;
               allow 127.0.0.1;
               deny all;
               fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
               include fastcgi_params;
               fastcgi_pass unix:/run/php/php-fpm.sock;
       }
}

TODO find out why monitoring via tcp socket 127.0.0.1:9001 doesn't work

Notes

SSL certificates

The host.crt goes first in the bundle


server {
 listen   443;
 ssl    on;
 ssl_certificate    /etc/ssl/your_domain_name.pem; (or bundle.crt)
 ssl_certificate_key    /etc/ssl/your_domain_name.key;
 server_name your.domain.com;
 access_log /var/log/nginx/nginx.vhost.access.log;
 error_log /var/log/nginx/nginx.vhost.error.log;
 location / {
  root   /home/www/public_html/your.domain.com/public/;
  index  index.html;
 }
}

HOWTO

SSL configuration

In case of letsencrypt check /etc/letsencrypt/options-ssl-nginx.conf

Cipher order

ssl_prefer_server_ciphers on;

Set server directives globally

Put them in /etc/nginx/conf.d/directives.conf

CSP

Content Security Policy

Examples ]

CSP config example

add_header Content-Security-Policy "
           default-src 'self';
           frame-src 'none';
           script-src 'self';
           frame-ancestors 'self';
           img-src 'self' data:;
           manifest-src 'self';
           media-src 'self';
           object-src 'self';
           base-uri: 'self';
           form-action: 'self';
           worker-src 'self';" always;

Client certificates

Create client certificate

openssl pkcs12 -export -inkey ./sample.key -in ./sample.crt -out ./sample.p12

Add client certificate to chromium

Add the .p12 in Advanced->Manage certificates->Your certificates

Logging

Log level

Doesn't seem to be documented, defaults to log all?

Ignore IP addresses in logs

Create /etc/nginx/conf.d/logignore.conf or put in your vhost config:

map $remote_addr $loggable {
   "1.2.3.4" 0;
   # allow rest
   default 1;
}

and then in your vhost configuration:

access_log /var/log/nginx/myhost.access.log combined if=$loggable;


Regular expression on $request

To filter out the nextcloud preview 404s:

map $request $loggable {
  "~^GET \/index\.php\/core\/preview.*$" 0;
  default 1;
}

Get configuration items

getconf PAGESIZE

Redirecting in nginx

https://www.liquidweb.com/kb/redirecting-urls-using-nginx/

enable ipv6

In server section add

listen [::]:443;

Configure buffer sizes

See https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size

Dump nginx configuration

nginx -T

Rate limiting


Limit access

https://docs.hypernode.com/hypernode-platform/nginx/how-to-block-allow-ip-addresses-in-nginx.html


nginx and OCSP (stapling)

To make sure everything works have *all* certificates in bundle.pem

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/pki/tls/certs/bundle.pem
ssl_certificate /etc/pki/tls/certs/bundle.pem;
ssl_certificate_key /etc/pki/tls/private/mydomain.key;


Letsencrypt and stapling

Will be discontinued: https://kbeezie.com/nginx-ssl_stapling-ignored-ocsp-letsencrypt/


Exclude not found from log

log_not_found off;


Allow zabbix to read nginx error log

setfacl -m g:zabbix:r /var/log/nginx/error.log

(perhaps put this in logrotate postrotate)

FAQ

php not executed but downloaded

In case of php-fpm see:

Security settings

X-Content-Type-Options

# ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
add_header X-Content-Type-Options nosniff always;

Content-Security-Policy (CSP)

security.txt

nginx serving wrong page

Forgot to tell it to listen on ipv6? Like

listen [::]:443 ssl;l

Conflicting server name XXX on 0.0.0.0:80

FastCGI sent in stderr: "Primary script unknown"

Usually means the php script just isn't there

Error messages

ERR_HTTP2_PROTOCOL_ERROR

Check with curl:

curl --http2 https://example.com

I got

curl: (92) : frame type: 1, stream: 1, Invalid HTTP header field was receivedname: [content-security-policy]

found out the hard way that add_header arguments have to be on single line

nginx: [emerg] unknown log format

Define log_format in http section before the includes.


upstream prematurely closed connection while reading upstream

Maybe trying to fetch a large file, like jpg?

client intended to send too large body

server {
  # default 1m
  client_max_body_size 4m;


no live upstreams while connecting to upstream

can't connect to whatever backend?


upstream sent too big header while reading response header from upstream

In case of fastcgi

https://gist.github.com/magnetikonline/11312172#determine-fastcgi-response-sizes

Try settings like

fastcgi_buffers 32 32k;
fastcgi_buffer_size 32k;

an upstream response is buffered to a temporary file

(SSL: error:141CF06C:SSL routines:tls_parse_ctos_key_share:bad key share) while SSL handshaking

Usually just a bad client or a scan.

cannot load certificate "/etc/ssl/certs/ssl-cert-snakeoil.pem

Probably ubuntu?

apt install ssl-cert

access forbidden by rule

look for allow or deny lines

a client request body is buffered to a temporary file

PLay some with

client_body_buffer_size 10M;
client_max_body_size 10M;

TODO check, this doesn't seem to apply If all else fails just set:

   proxy_max_temp_file_size 0;

and see if you get some feedback :)

upstream timed out

Look for proxy_pass


failed (104: Unknown error) while reading response header from upstream

[emerg] duplicate listen options for [::]:443

looks like "ipv6only=on" added by letsencrypt causes that, removing it might help

nginx: [emerg] a duplicate default server for 0.0.0.0:80

Multiple vhosts having "default_server" in their listen lines


nginx: [error] invalid PID number "" in "/run/nginx.pid"

Try

systemctl restart nginx

upstream sent no valid HTTP/1.0

Check for confusion between http and https