Nginx¶
Inhalt¶
- Nginx 1.28.2
- Webserver für statische Inhalte, Redirects und TLS
- PHP-FPM-Anbindung per Unix-Socket
- HTTP/2
- optional HTTP/3
- optional Brotli
Einleitung¶
Dieses HowTo beschreibt die Installation und Konfiguration von Nginx auf FreeBSD 15+ als Webserver für statische Inhalte, Redirects, TLS und PHP-FPM über Unix-Socket.
Dieses HowTo verwendet bewusst den Port www/nginx. Der aktuelle Portstand ist 1.28.2. Der Port bringt bereits die üblichen Beispielkonfigurationen wie nginx.conf-dist, fastcgi_params-dist und mime.types-dist mit. In den Default-Optionen sind HTTPV2 und HTTPV3 enthalten; Brotli gehört dagegen nicht zu den Standardoptionen und muss bewusst zusätzlich gewählt werden. (freshports.org)
Nginx liest seine Hauptkonfiguration aus nginx.conf. Änderungen an der Konfiguration werden erst nach Reload oder Restart wirksam. Für die PHP-Anbindung verwendet Nginx fastcgi_pass; dabei kann statt TCP ausdrücklich auch ein Unix-Domain-Socket verwendet werden. (Nginx)
Voraussetzungen¶
Zu den Voraussetzungen für dieses HowTo siehe bitte: Hosting System
Zusätzlich gilt für dieses HowTo:
- Nginx ist der öffentliche Webserver auf Port 80 und 443.
- PHP-FPM ist bereits installiert.
- PHP-FPM lauscht tatsächlich auf dem konfigurierten Unix-Socket, zum Beispiel
/var/run/fpm_www.sock. - Für produktiven TLS-Betrieb liegen die Zertifikate bereits unter
/usr/local/etc/letsencrypt/live/.... - Falls HTTP/3 später aktiviert werden soll, muss zusätzlich QUIC konfiguriert werden. Dafür braucht Nginx einen eigenen
listen ... quic-Listener; QUIC verwendet dabei UDP als Transport. (Nginx)
Vorbereitungen¶
DNS Records¶
Für dieses HowTo müssen zuvor folgende DNS-Records angelegt werden, sofern sie noch nicht existieren, oder entsprechend geändert werden, sofern sie bereits existieren.
example.com. IN A __IPADDR4__
example.com. IN AAAA __IPADDR6__
www.example.com. IN A __IPADDR4__
www.example.com. IN AAAA __IPADDR6__
mail.example.com. IN A __IPADDR4__
mail.example.com. IN AAAA __IPADDR6__
Gruppen / Benutzer / Passwörter¶
Für dieses HowTo sind keine zusätzlichen Systemgruppen, Systembenutzer oder Passwörter erforderlich.
Verzeichnisse / Dateien¶
Für dieses HowTo müssen zuvor folgende Verzeichnisse angelegt werden, sofern sie noch nicht existieren, oder entsprechend geändert werden, sofern sie bereits existieren.
install -d -m 1777 -o www -g www /usr/local/www/cache
install -d -m 1777 -o www -g www /usr/local/www/tmp
mkdir -p /usr/local/www/vhosts/0default0/conf
mkdir -p /usr/local/www/vhosts/0default0/cron
mkdir -p /usr/local/www/vhosts/0default0/logs
mkdir -p /usr/local/www/vhosts/0default0/data/.well-known
mkdir -p /usr/local/www/vhosts/mail.example.com/conf
mkdir -p /usr/local/www/vhosts/mail.example.com/cron
mkdir -p /usr/local/www/vhosts/mail.example.com/logs
mkdir -p /usr/local/www/vhosts/mail.example.com/data/.well-known
mkdir -p /usr/local/www/vhosts/www.example.com/conf
mkdir -p /usr/local/www/vhosts/www.example.com/cron
mkdir -p /usr/local/www/vhosts/www.example.com/logs
mkdir -p /usr/local/www/vhosts/www.example.com/data/.well-known
mkdir -p /usr/local/etc/newsyslog.conf.d
Für diese HowTos müssen zuvor folgende Dateien angelegt werden, sofern sie noch nicht existieren, oder entsprechend geändert werden, sofern sie bereits existieren.
Installation¶
Wir installieren www/nginx und dessen Abhängigkeiten.¶
mkdir -p /var/db/ports/devel_google-perftools
cat <<'EOF' > /var/db/ports/devel_google-perftools/options
_OPTIONS_READ=google-perftools-2.17.2
_FILE_COMPLETE_OPTIONS_LIST=DOCS PROFILER PAGE8K PAGE32K PAGE64K ALIGN8 ALIGN16
OPTIONS_FILE_UNSET+=DOCS
OPTIONS_FILE_SET+=PROFILER
OPTIONS_FILE_UNSET+=PAGE8K
OPTIONS_FILE_SET+=PAGE32K
OPTIONS_FILE_UNSET+=PAGE64K
OPTIONS_FILE_UNSET+=ALIGN8
OPTIONS_FILE_SET+=ALIGN16
EOF
mkdir -p /var/db/ports/www_nginx
cat <<'EOF' > /var/db/ports/www_nginx/options
_OPTIONS_READ=nginx-1.28.2
_FILE_COMPLETE_OPTIONS_LIST=DEBUG DEBUGLOG DSO FILE_AIO IPV6 NJS NJS_XML OTEL THREADS WWW GSSAPI_HEIMDAL GSSAPI_MIT GOOGLE_PERFTOOLS HTTP HTTP_ADDITION HTTP_AUTH_REQ HTTP_CACHE HTTP_DAV HTTP_DEGRADATION HTTP_FLV HTTP_GUNZIP_FILTER HTTP_GZIP_STATIC HTTP_IMAGE_FILTER HTTP_MP4 HTTP_PERL HTTP_RANDOM_INDEX HTTP_REALIP HTTP_SECURE_LINK HTTP_SLICE HTTP_SSL HTTP_STATUS HTTP_SUB HTTP_XSLT HTTPV2 HTTPV3 HTTPV3_BORING HTTPV3_LSSL HTTPV3_QTLS MAIL MAIL_IMAP MAIL_POP3 MAIL_SMTP MAIL_SSL STREAM STREAM_REALIP STREAM_SSL STREAM_SSL_PREREAD AJP AWS_AUTH BROTLI CACHE_PURGE DEVEL_KIT ARRAYVAR DRIZZLE DYNAMIC_UPSTREAM ECHO ENCRYPTSESSION FIPS_CHECK FORMINPUT GRIDFS HEADERS_MORE HTTP_ACCEPT_LANGUAGE HTTP_AUTH_DIGEST HTTP_AUTH_KRB5 HTTP_AUTH_LDAP HTTP_AUTH_PAM HTTP_DAV_EXT HTTP_EVAL HTTP_FANCYINDEX HTTP_FOOTER HTTP_GEOIP2 HTTP_IP2LOCATION HTTP_IP2PROXY HTTP_JSON_STATUS HTTP_MOGILEFS HTTP_NOTICE HTTP_PUSH HTTP_PUSH_STREAM HTTP_REDIS HTTP_SLICE_AHEAD HTTP_SUBS_FILTER HTTP_TARANTOOL HTTP_UPLOAD HTTP_UPLOAD_PROGRESS HTTP_UPSTREAM_CHECK HTTP_UPSTREAM_FAIR HTTP_UPSTREAM_STICKY HTTP_VIDEO_THUMBEXTRACTOR HTTP_ZIP ICONV LET LINK LUA LUASTREAM MEMC MODSECURITY3 NAXSI PASSENGER POSTGRES RDS_CSV RDS_JSON REDIS2 RTMP SET_MISC SFLOW SHIBBOLETH SLOWFS_CACHE SRCACHE STS VOD VTS XSS WEBSOCKIFY ZSTD
OPTIONS_FILE_UNSET+=DEBUG
OPTIONS_FILE_UNSET+=DEBUGLOG
OPTIONS_FILE_SET+=DSO
OPTIONS_FILE_SET+=FILE_AIO
OPTIONS_FILE_SET+=IPV6
OPTIONS_FILE_UNSET+=NJS
OPTIONS_FILE_UNSET+=NJS_XML
OPTIONS_FILE_UNSET+=OTEL
OPTIONS_FILE_SET+=THREADS
OPTIONS_FILE_SET+=WWW
OPTIONS_FILE_UNSET+=GSSAPI_HEIMDAL
OPTIONS_FILE_UNSET+=GSSAPI_MIT
OPTIONS_FILE_SET+=GOOGLE_PERFTOOLS
OPTIONS_FILE_SET+=HTTP
OPTIONS_FILE_SET+=HTTP_ADDITION
OPTIONS_FILE_SET+=HTTP_AUTH_REQ
OPTIONS_FILE_SET+=HTTP_CACHE
OPTIONS_FILE_SET+=HTTP_DAV
OPTIONS_FILE_UNSET+=HTTP_DEGRADATION
OPTIONS_FILE_SET+=HTTP_FLV
OPTIONS_FILE_SET+=HTTP_GUNZIP_FILTER
OPTIONS_FILE_SET+=HTTP_GZIP_STATIC
OPTIONS_FILE_UNSET+=HTTP_IMAGE_FILTER
OPTIONS_FILE_SET+=HTTP_MP4
OPTIONS_FILE_UNSET+=HTTP_PERL
OPTIONS_FILE_SET+=HTTP_RANDOM_INDEX
OPTIONS_FILE_SET+=HTTP_REALIP
OPTIONS_FILE_SET+=HTTP_SECURE_LINK
OPTIONS_FILE_SET+=HTTP_SLICE
OPTIONS_FILE_SET+=HTTP_SSL
OPTIONS_FILE_SET+=HTTP_STATUS
OPTIONS_FILE_SET+=HTTP_SUB
OPTIONS_FILE_SET+=HTTP_XSLT
OPTIONS_FILE_SET+=HTTPV2
OPTIONS_FILE_SET+=HTTPV3
OPTIONS_FILE_UNSET+=HTTPV3_BORING
OPTIONS_FILE_UNSET+=HTTPV3_LSSL
OPTIONS_FILE_UNSET+=HTTPV3_QTLS
OPTIONS_FILE_UNSET+=MAIL
OPTIONS_FILE_UNSET+=MAIL_IMAP
OPTIONS_FILE_UNSET+=MAIL_POP3
OPTIONS_FILE_UNSET+=MAIL_SMTP
OPTIONS_FILE_UNSET+=MAIL_SSL
OPTIONS_FILE_SET+=STREAM
OPTIONS_FILE_SET+=STREAM_REALIP
OPTIONS_FILE_SET+=STREAM_SSL
OPTIONS_FILE_SET+=STREAM_SSL_PREREAD
OPTIONS_FILE_UNSET+=AJP
OPTIONS_FILE_UNSET+=AWS_AUTH
OPTIONS_FILE_SET+=BROTLI
OPTIONS_FILE_UNSET+=CACHE_PURGE
OPTIONS_FILE_SET+=DEVEL_KIT
OPTIONS_FILE_UNSET+=ARRAYVAR
OPTIONS_FILE_UNSET+=DRIZZLE
OPTIONS_FILE_UNSET+=DYNAMIC_UPSTREAM
OPTIONS_FILE_UNSET+=ECHO
OPTIONS_FILE_UNSET+=ENCRYPTSESSION
OPTIONS_FILE_UNSET+=FIPS_CHECK
OPTIONS_FILE_UNSET+=FORMINPUT
OPTIONS_FILE_UNSET+=GRIDFS
OPTIONS_FILE_UNSET+=HEADERS_MORE
OPTIONS_FILE_UNSET+=HTTP_ACCEPT_LANGUAGE
OPTIONS_FILE_UNSET+=HTTP_AUTH_DIGEST
OPTIONS_FILE_UNSET+=HTTP_AUTH_KRB5
OPTIONS_FILE_UNSET+=HTTP_AUTH_LDAP
OPTIONS_FILE_UNSET+=HTTP_AUTH_PAM
OPTIONS_FILE_UNSET+=HTTP_DAV_EXT
OPTIONS_FILE_UNSET+=HTTP_EVAL
OPTIONS_FILE_UNSET+=HTTP_FANCYINDEX
OPTIONS_FILE_UNSET+=HTTP_FOOTER
OPTIONS_FILE_UNSET+=HTTP_GEOIP2
OPTIONS_FILE_UNSET+=HTTP_IP2LOCATION
OPTIONS_FILE_UNSET+=HTTP_IP2PROXY
OPTIONS_FILE_UNSET+=HTTP_JSON_STATUS
OPTIONS_FILE_UNSET+=HTTP_MOGILEFS
OPTIONS_FILE_UNSET+=HTTP_NOTICE
OPTIONS_FILE_UNSET+=HTTP_PUSH
OPTIONS_FILE_UNSET+=HTTP_PUSH_STREAM
OPTIONS_FILE_UNSET+=HTTP_REDIS
OPTIONS_FILE_UNSET+=HTTP_SLICE_AHEAD
OPTIONS_FILE_UNSET+=HTTP_SUBS_FILTER
OPTIONS_FILE_UNSET+=HTTP_TARANTOOL
OPTIONS_FILE_UNSET+=HTTP_UPLOAD
OPTIONS_FILE_UNSET+=HTTP_UPLOAD_PROGRESS
OPTIONS_FILE_UNSET+=HTTP_UPSTREAM_CHECK
OPTIONS_FILE_UNSET+=HTTP_UPSTREAM_FAIR
OPTIONS_FILE_UNSET+=HTTP_UPSTREAM_STICKY
OPTIONS_FILE_UNSET+=HTTP_VIDEO_THUMBEXTRACTOR
OPTIONS_FILE_UNSET+=HTTP_ZIP
OPTIONS_FILE_SET+=ICONV
OPTIONS_FILE_UNSET+=LET
OPTIONS_FILE_UNSET+=LINK
OPTIONS_FILE_UNSET+=LUA
OPTIONS_FILE_UNSET+=LUASTREAM
OPTIONS_FILE_UNSET+=MEMC
OPTIONS_FILE_UNSET+=MODSECURITY3
OPTIONS_FILE_UNSET+=NAXSI
OPTIONS_FILE_UNSET+=PASSENGER
OPTIONS_FILE_UNSET+=POSTGRES
OPTIONS_FILE_UNSET+=RDS_CSV
OPTIONS_FILE_UNSET+=RDS_JSON
OPTIONS_FILE_UNSET+=REDIS2
OPTIONS_FILE_UNSET+=RTMP
OPTIONS_FILE_UNSET+=SET_MISC
OPTIONS_FILE_UNSET+=SFLOW
OPTIONS_FILE_UNSET+=SHIBBOLETH
OPTIONS_FILE_UNSET+=SLOWFS_CACHE
OPTIONS_FILE_UNSET+=SRCACHE
OPTIONS_FILE_UNSET+=STS
OPTIONS_FILE_UNSET+=VOD
OPTIONS_FILE_UNSET+=VTS
OPTIONS_FILE_UNSET+=XSS
OPTIONS_FILE_UNSET+=WEBSOCKIFY
OPTIONS_FILE_SET+=ZSTD
EOF
portmaster -w -B -g -U --force-config www/nginx -n
Dienst in rc.conf eintragen¶
Der Dienst wird mittels sysrc in der rc.conf eingetragen und dadurch beim Systemstart automatisch gestartet.
Logrotation einrichten¶
Konfiguration¶
Konfigurationsdateien¶
Der Port liefert bereits Beispielkonfigurationen mit. Die zentrale Konfiguration liegt unter /usr/local/etc/nginx/nginx.conf; zusätzliche Dateien wie vhosts.conf und vhosts-ssl.conf können über include eingebunden werden. Änderungen werden erst nach reload oder restart wirksam. (freshports.org)
cat <<'EOF' > /usr/local/etc/nginx/nginx.conf
user www;
worker_processes auto;
pid /var/run/nginx.pid;
error_log /var/log/nginx/error.log;
events {
worker_connections 4096;
}
http {
include mime.types;
default_type application/octet-stream;
log_format combined
'$host $remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'"$http_x_forwarded_for"';
log_format combinedssl
'$host $remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'"$http_x_forwarded_for" "$ssl_protocol" "$ssl_cipher"';
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 2s;
keepalive_requests 500;
server_tokens off;
charset utf-8;
gzip on;
gzip_vary on;
gzip_http_version 1.1;
gzip_proxied any;
gzip_min_length 1024;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/ld+json
application/manifest+json
application/xml
application/xhtml+xml
application/rss+xml
application/atom+xml
image/svg+xml
image/vnd.microsoft.icon;
brotli on;
brotli_comp_level 5;
brotli_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/ld+json
application/manifest+json
application/xml
application/xhtml+xml
application/rss+xml
application/atom+xml
image/svg+xml
image/vnd.microsoft.icon;
include /usr/local/etc/nginx/vhosts.conf;
include /usr/local/etc/nginx/vhosts-ssl.conf;
}
EOF
cat <<'EOF' > /usr/local/etc/nginx/vhosts.conf
server {
listen 127.0.0.1:80;
server_name localhost;
access_log /usr/local/www/vhosts/0localhost0/logs/nginx_access_log combined;
error_log /usr/local/www/vhosts/0localhost0/logs/nginx_error_log warn;
root /usr/local/www/vhosts/0localhost0/data;
index index.html index.htm index.php;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
location = /.well-known/server-status {
stub_status;
allow 127.0.0.1;
allow ::1;
deny all;
}
error_page 404 /404.html;
location = /404.html {
root /usr/local/www/nginx-dist;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
location ^~ /.well-known/acme-challenge/ {
root /usr/local/www;
default_type text/plain;
try_files $uri =404;
}
location ~ /\.(?!well-known/acme-challenge/) {
return 404;
}
location / {
try_files $uri $uri/ =404;
}
location ~ /\.ht {
deny all;
}
}
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name devnull.example.com _;
access_log /usr/local/www/vhosts/0default0/logs/nginx_access_log combined;
error_log /usr/local/www/vhosts/0default0/logs/nginx_error_log warn;
root /usr/local/www/vhosts/0default0/data;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
location = /.well-known/server-status {
stub_status;
allow 127.0.0.1;
allow ::1;
deny all;
}
error_page 404 /404.html;
location = /404.html {
root /usr/local/www/nginx-dist;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
location ^~ /.well-known/acme-challenge/ {
root /usr/local/www;
default_type text/plain;
try_files $uri =404;
}
location ~ /\.(?!well-known/acme-challenge/) {
return 404;
}
location / {
try_files $uri $uri/ =404;
}
location ~ /\.ht {
deny all;
}
return 308 https://devnull.example.com$request_uri;
}
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
access_log /usr/local/www/vhosts/www.example.com/logs/nginx_access_log combined;
error_log /usr/local/www/vhosts/www.example.com/logs/nginx_error_log warn;
root /usr/local/www/vhosts/www.example.com/data;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
location = /.well-known/server-status {
stub_status;
allow 127.0.0.1;
allow ::1;
deny all;
}
error_page 404 /404.html;
location = /404.html {
root /usr/local/www/nginx-dist;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
location ^~ /.well-known/acme-challenge/ {
root /usr/local/www;
default_type text/plain;
try_files $uri =404;
}
location ~ /\.(?!well-known/acme-challenge/) {
return 404;
}
location / {
try_files $uri $uri/ =404;
}
location ~ /\.ht {
deny all;
}
return 308 https://www.example.com$request_uri;
}
server {
listen 80;
listen [::]:80;
server_name mail.example.com;
access_log /usr/local/www/vhosts/mail.example.com/logs/nginx_access_log combined;
error_log /usr/local/www/vhosts/mail.example.com/logs/nginx_error_log warn;
root /usr/local/www/vhosts/mail.example.com/data;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
error_page 404 /404.html;
location = /404.html {
root /usr/local/www/nginx-dist;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
location = /.well-known/server-status {
stub_status;
allow 127.0.0.1;
allow ::1;
deny all;
}
location ^~ /.well-known/acme-challenge/ {
root /usr/local/www;
default_type text/plain;
try_files $uri =404;
}
location ~ /\.(?!well-known/acme-challenge/) {
return 404;
}
location / {
try_files $uri $uri/ =404;
}
location ~ /\.ht {
deny all;
}
return 308 https://mail.example.com$request_uri;
}
EOF
cat <<'EOF' > /usr/local/etc/nginx/vhosts-ssl.conf
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
http2 on;
server_name devnull.example.com _;
access_log /usr/local/www/vhosts/0default0/logs/nginx_ssl_access_log combinedssl;
error_log /usr/local/www/vhosts/0default0/logs/nginx_ssl_error_log warn;
root /usr/local/www/vhosts/0default0/data;
index index.html index.htm index.php;
ssl_certificate /usr/local/etc/letsencrypt/live/devnull.example.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/devnull.example.com/privkey.pem;
ssl_trusted_certificate /usr/local/etc/letsencrypt/live/devnull.example.com/chain.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
ssl_ecdh_curve X448:X25519:secp384r1:prime256v1:secp521r1;
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.1 [::1] valid=300s;
resolver_timeout 2s;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
location = /.well-known/server-status {
stub_status;
allow 127.0.0.1;
allow ::1;
deny all;
}
error_page 404 /404.html;
location = /404.html {
root /usr/local/www/nginx-dist;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
location ^~ /.well-known/acme-challenge/ {
root /usr/local/www;
default_type text/plain;
try_files $uri =404;
}
location ~ /\.(?!well-known/acme-challenge/) {
return 404;
}
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
fastcgi_param HTTPS on;
fastcgi_pass unix:/var/run/fpm_www.sock;
}
location ~ /\.ht {
deny all;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name example.com;
ssl_certificate /usr/local/etc/letsencrypt/live/www.example.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/www.example.com/privkey.pem;
return 308 https://www.example.com$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name www.example.com;
access_log /usr/local/www/vhosts/www.example.com/logs/nginx_ssl_access_log combinedssl;
error_log /usr/local/www/vhosts/www.example.com/logs/nginx_ssl_error_log warn;
root /usr/local/www/vhosts/www.example.com/data;
index index.html index.htm index.php;
ssl_certificate /usr/local/etc/letsencrypt/live/www.example.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/www.example.com/privkey.pem;
ssl_trusted_certificate /usr/local/etc/letsencrypt/live/www.example.com/chain.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
ssl_ecdh_curve X448:X25519:secp384r1:prime256v1:secp521r1;
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.1 [::1] valid=300s;
resolver_timeout 2s;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
location = /.well-known/server-status {
stub_status;
allow 127.0.0.1;
allow ::1;
deny all;
}
error_page 404 /404.html;
location = /404.html {
root /usr/local/www/nginx-dist;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
location ^~ /.well-known/acme-challenge/ {
root /usr/local/www;
default_type text/plain;
try_files $uri =404;
}
location ~ /\.(?!well-known/acme-challenge/) {
return 404;
}
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
fastcgi_param HTTPS on;
fastcgi_pass unix:/var/run/fpm_www.sock;
}
location ~ /\.ht {
deny all;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name mail.example.com;
access_log /usr/local/www/vhosts/mail.example.com/logs/nginx_ssl_access_log combinedssl;
error_log /usr/local/www/vhosts/mail.example.com/logs/nginx_ssl_error_log warn;
root /usr/local/www/vhosts/mail.example.com/data;
index index.html index.htm index.php;
ssl_certificate /usr/local/etc/letsencrypt/live/mail.example.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/mail.example.com/privkey.pem;
ssl_trusted_certificate /usr/local/etc/letsencrypt/live/mail.example.com/chain.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
ssl_ecdh_curve X448:X25519:secp384r1:prime256v1:secp521r1;
ssl_stapling on;
ssl_stapling_verify on;
resolver 127.0.0.1 [::1] valid=300s;
resolver_timeout 2s;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Permitted-Cross-Domain-Policies "none" always;
location = /.well-known/server-status {
stub_status;
allow 127.0.0.1;
allow ::1;
deny all;
}
error_page 404 /404.html;
location = /404.html {
root /usr/local/www/nginx-dist;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
location ^~ /.well-known/acme-challenge/ {
root /usr/local/www;
default_type text/plain;
try_files $uri =404;
}
location ~ /\.(?!well-known/acme-challenge/) {
return 404;
}
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
fastcgi_param HTTPS on;
fastcgi_pass unix:/var/run/fpm_www.sock;
}
location ~ /\.ht {
deny all;
}
}
EOF
HTTP/2¶
Für aktuelles Nginx wird HTTP/2 über die Direktive http2 on; aktiviert. Seit Nginx 1.25.1 ist der alte http2-Parameter an listen deprecated. Das passt zu deinem ursprünglichen Hinweis und sollte in den VHosts genauso umgesetzt werden. (Nginx)
HTTP/3 nur bei Bedarf¶
HTTP/3 ist in Nginx ein eigener Modulpfad. Das offizielle ngx_http_v3_module wird weiterhin als experimental dokumentiert. Zusätzlich reicht ein Build mit HTTP/3-Unterstützung allein nicht aus: du brauchst einen separaten QUIC-Listener wie listen 443 quic reuseport;. Die offizielle Dokumentation empfiehlt außerdem, für HTTP/3 und HTTPS denselben Port zu verwenden. (Nginx)
Wenn du HTTP/3 nicht gezielt brauchst, aktiviere zunächst nur HTTP/2 und nimm QUIC später separat in Betrieb.
PHP-FPM über Unix-Socket¶
Für PHP-FPM ist die FastCGI-Anbindung per Unix-Socket fachlich korrekt. Nginx unterstützt bei fastcgi_pass ausdrücklich Socket-Pfade im Format unix:/pfad/zur.sock. Genau deshalb muss der in deiner Nginx-Konfiguration eingetragene Socket-Pfad wirklich zum laufenden PHP-FPM-Pool passen. (Nginx)
fixperms.sh einrichten¶
cat <<'EOF' > /usr/local/www/vhosts/0default0/cron/fixperms.sh
#!/bin/sh
DIR="$(dirname $0)"
chown -R root:wheel $DIR/../conf
chown -R root:wheel $DIR/../logs
chown -R www:www $DIR/../cron
chown -R www:www $DIR/../data
find $DIR/../conf/ -type d -print0 | xargs -0 chmod 0755
find $DIR/../conf/ -type f -print0 | xargs -0 chmod 0664
find $DIR/../logs/ -type d -print0 | xargs -0 chmod 0755
find $DIR/../logs/ -type f -print0 | xargs -0 chmod 0664
find $DIR/../cron/ -type d -print0 | xargs -0 chmod 0755
find $DIR/../cron/ -type f -print0 | xargs -0 chmod 0755
find $DIR/../data/ -type d -print0 | xargs -0 chmod 6750
find $DIR/../data/ -type f -print0 | xargs -0 chmod 0640
exit 0
EOF
chmod 750 /usr/local/www/vhosts/0default0/cron/fixperms.sh
cat <<'EOF' > /usr/local/www/vhosts/mail.example.com/cron/fixperms.sh
#!/bin/sh
DIR="$(dirname $0)"
chown -R root:wheel $DIR/../conf
chown -R root:wheel $DIR/../logs
chown -R www:www $DIR/../cron
chown -R www:www $DIR/../data
find $DIR/../conf/ -type d -print0 | xargs -0 chmod 0755
find $DIR/../conf/ -type f -print0 | xargs -0 chmod 0664
find $DIR/../logs/ -type d -print0 | xargs -0 chmod 0755
find $DIR/../logs/ -type f -print0 | xargs -0 chmod 0664
find $DIR/../cron/ -type d -print0 | xargs -0 chmod 0755
find $DIR/../cron/ -type f -print0 | xargs -0 chmod 0755
find $DIR/../data/ -type d -print0 | xargs -0 chmod 6750
find $DIR/../data/ -type f -print0 | xargs -0 chmod 0640
exit 0
EOF
chmod 750 /usr/local/www/vhosts/mail.example.com/cron/fixperms.sh
cat <<'EOF' > /usr/local/www/vhosts/www.example.com/cron/fixperms.sh
#!/bin/sh
DIR="$(dirname $0)"
chown -R root:wheel $DIR/../conf
chown -R root:wheel $DIR/../logs
chown -R www:www $DIR/../cron
chown -R www:www $DIR/../data
find $DIR/../conf/ -type d -print0 | xargs -0 chmod 0755
find $DIR/../conf/ -type f -print0 | xargs -0 chmod 0664
find $DIR/../logs/ -type d -print0 | xargs -0 chmod 0755
find $DIR/../logs/ -type f -print0 | xargs -0 chmod 0664
find $DIR/../cron/ -type d -print0 | xargs -0 chmod 0755
find $DIR/../cron/ -type f -print0 | xargs -0 chmod 0755
find $DIR/../data/ -type d -print0 | xargs -0 chmod 6750
find $DIR/../data/ -type f -print0 | xargs -0 chmod 0640
exit 0
EOF
chmod 750 /usr/local/www/vhosts/www.example.com/cron/fixperms.sh
Konfiguration prüfen¶
Vor dem ersten Start sollte die Konfiguration immer geprüft werden. nginx -t prüft Syntax und grundlegende Konsistenz. Änderungen an der Konfiguration werden von Nginx erst nach Reload oder Restart übernommen; beim Reload validiert der Master-Prozess die neue Konfiguration zuerst und rollt bei Fehlern auf die alte zurück. (Nginx)
Für HTTP/2 und optionale HTTP/3-/Brotli-Nutzung solltest du lokal zusätzlich prüfen, ob der Port wirklich mit den gewünschten Modulen gebaut wurde.
Datenbanken¶
Für dieses HowTo sind keine Datenbanken erforderlich.
Zusatzsoftware¶
Mögliche Zusatzsoftware wird hier installiert und konfiguriert.
Für dieses HowTo ist keine zusätzliche Software erforderlich.
Brotli bleibt eine bewusste Zusatzentscheidung. Im Standard-Port www/nginx ist es nicht Teil der Default-Optionen. (GitHub)
Aufräumen¶
Überflüssige oder temporäre Verzeichnisse und Dateien entsorgen.
Zusatzsoftware Installation¶
Nicht erforderlich.
Zusatzsoftware Konfiguration¶
Nicht erforderlich.
Abschluss¶
Nginx kann nun gestartet werden.
Für spätere Änderungen:
Nginx übernimmt Änderungen an Konfigurationsdateien erst nach einem Reload oder Restart. Beim Reload werden neue Worker nur dann gestartet, wenn die neue Konfiguration gültig ist. (Nginx)
Referenzen¶
- FreeBSD FreshPorts:
www/nginx(freshports.org) - Nginx Beginner’s Guide (Nginx)
- Nginx Runtime Control / Reload-Verhalten (Nginx)
- Nginx
ngx_http_fastcgi_module(Nginx) - Nginx
ngx_http_v2_module(Nginx) - Nginx CHANGES 1.25.1 (
http2-Direktive, Deprecation vonlisten ... http2) (Nginx) - Nginx QUIC / HTTP/3 (Nginx)