Nginx: Difference between revisions
m →FAQ Tag: wikieditor |
m →HOWTO |
||
| (42 intermediate revisions by the same user not shown) | |||
| Line 9: | Line 9: | ||
==Nginx and php-fpm== | ==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] | *[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 31: | 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 | ||
| Line 43: | Line 137: | ||
==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] | |||
*https://securitytxt.org/ | |||
==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" == | ==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=== | ===no live upstreams while connecting to upstream=== | ||
can't connect to whatever backend? | can't connect to whatever backend? | ||
| Line 58: | Line 231: | ||
*[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=== | ===an upstream response is buffered to a temporary file=== | ||
| Line 65: | Line 244: | ||
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 79: | Line 261: | ||
and see if you get some feedback :) | 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 | |||
[[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
- onfiguring HTTPS servers
- Security/Server Side TLS Mozilla: Security/Server Side TLS]
- 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
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
