Initial file upload
Signed-off-by: Tommy <contact@tommytran.io>
This commit is contained in:
parent
5f01f742fa
commit
1bf7d1835f
18
README.md
Normal file
18
README.md
Normal file
@ -0,0 +1,18 @@
|
||||
# NGINX Configs
|
||||
|
||||
These are my NGINX configurations. They are written for Fedora CoreOS's NGINX build with `nginx-mod-stream`.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Install `nginx`, `nginx-mod-stream`, and `policycoreutils-python-utils` on Fedora. Makesure `rsync` is available on the OS.
|
||||
2. Comment out the default server block in `/etc/nginx/nginx.conf`.
|
||||
3. Copy all configuration files in `/etc/nginx` except the ones named `/etc/nginx/conf.d/sites_.*` to the corresponding location onto the server.
|
||||
4. Run `setup.sh`
|
||||
5. Make a dummy vhost listening on port `80` with the server_name you want.
|
||||
6. Generate certificates with the example in the certbot directory.
|
||||
7. Copy `/etc/nginx/conf.d/sites_default.conf` to `/etc/nginx/conf.d` for https redirection.
|
||||
8. Make your actual vhost config based on the `sites_.*` samples in `/etc/nginx/conf.d/sites_default.conf`.
|
||||
|
||||
## Notes
|
||||
|
||||
This is used on my tunnel servers with multiple IP addresses. Hence, you may see addresses like `ipv4_1` and `ipv4_2`. Just replace them with your own ip addresses.
|
5
certbot/uptime-kuma
Normal file
5
certbot/uptime-kuma
Normal file
@ -0,0 +1,5 @@
|
||||
certbot certonly --webroot --webroot-path /srv/nginx --no-eff-email \
|
||||
--key-type ecdsa --reuse-key --must-staple \
|
||||
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
|
||||
--cert-name uptime.yourdomain.tld \
|
||||
-d uptime.yourdomain.tld
|
3
etc/nginx/conf.d/http2.conf
Normal file
3
etc/nginx/conf.d/http2.conf
Normal file
@ -0,0 +1,3 @@
|
||||
# This is all it takes to enable http2 globally
|
||||
|
||||
http2 on;
|
10
etc/nginx/conf.d/sites_default.conf
Normal file
10
etc/nginx/conf.d/sites_default.conf
Normal file
@ -0,0 +1,10 @@
|
||||
server {
|
||||
listen ipv4_1:80 default_server;
|
||||
listen [ipv6_1]:80 default_server;
|
||||
|
||||
include snippets/universal_paths.conf;
|
||||
|
||||
location / {
|
||||
return 308 https://$host$request_uri;
|
||||
}
|
||||
}
|
27
etc/nginx/conf.d/sites_uptime-kuma.conf
Normal file
27
etc/nginx/conf.d/sites_uptime-kuma.conf
Normal file
@ -0,0 +1,27 @@
|
||||
# This file assumes you have an uptime kuma instance running on the server
|
||||
|
||||
server {
|
||||
listen ipv4_1:443 quic reuseport;
|
||||
listen ipv4_1:443 ssl;
|
||||
listen ipv6_1:443 quic reuseport;
|
||||
listen ipv6_1:443 ssl;
|
||||
|
||||
server_name uptime.yourdomain.tld;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/uptime.yourdomain.tld/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/uptime.yourdomain.tld/privkey.pem;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/uptime.yourdomain.tld/chain.pem;
|
||||
ssl_stapling_file /var/cache/certbot-ocsp-fetcher/uptime.yourdomain.tld.der;
|
||||
|
||||
include snippets/universal_paths.conf;
|
||||
include snippets/hsts.conf;
|
||||
include snippets/security.conf;
|
||||
include snippets/quic.conf;
|
||||
include snippets/proxy.conf;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
add_header Content-Security-Policy "default-src 'none'; connect-src 'self'; img-src 'self' data:; frame-src 'self'; manifest-src 'self'; object-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; base-uri 'none'; block-all-mixed-content; form-action 'none'; frame-ancestors 'self'; upgrade-insecure-requests";
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3001;
|
||||
}
|
||||
}
|
31
etc/nginx/conf.d/tls.conf
Normal file
31
etc/nginx/conf.d/tls.conf
Normal file
@ -0,0 +1,31 @@
|
||||
# Shared TLS configuration
|
||||
|
||||
## Use strong ciphers
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_conf_command Options PrioritizeChaCha;
|
||||
|
||||
## Configure ssl session cache
|
||||
## Improves performance but we don't wanna keep this forever
|
||||
## Session ticket creation and rotation is handled by GrapheneOS's scripts:
|
||||
## https://github.com/GrapheneOS/infrastructure/blob/main/nginx-create-session-ticket-keys
|
||||
## https://github.com/GrapheneOS/infrastructure/blob/main/nginx-rotate-session-ticket-keys
|
||||
|
||||
ssl_session_cache shared:SSL:10m; # About 40000 sessions
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_ticket_key session-ticket-keys/4.key;
|
||||
ssl_session_ticket_key session-ticket-keys/3.key;
|
||||
ssl_session_ticket_key session-ticket-keys/2.key;
|
||||
ssl_session_ticket_key session-ticket-keys/1.key;
|
||||
|
||||
## Enable OCSP Stapling
|
||||
## We will use GrapheneOS's OCSP Fetcher to get the stapling file: https://github.com/GrapheneOS/infrastructure/blob/main/certbot-ocsp-fetcher
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
## The following settings need to be declared manually per vhost:
|
||||
# ssl_certificate
|
||||
# ssl_certificate_key
|
||||
# ssl_trusted_certificate
|
||||
# ssl_stapling_file
|
5
etc/nginx/snippets/hsts.conf
Normal file
5
etc/nginx/snippets/hsts.conf
Normal file
@ -0,0 +1,5 @@
|
||||
# Enable HSTS header
|
||||
# Only add this to server blocks with TLS
|
||||
|
||||
proxy_hide_header Strict-Transport-Security;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
27
etc/nginx/snippets/proxy.conf
Normal file
27
etc/nginx/snippets/proxy.conf
Normal file
@ -0,0 +1,27 @@
|
||||
# Proxy Header Settings
|
||||
# Use this with all reverse proxy vhosts
|
||||
|
||||
# Force http 1.1, anything not supporting it shouldn't be used
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# Replay attack mitigation for early data
|
||||
proxy_set_header Early-Data $ssl_early_data;
|
||||
|
||||
# Restore visitor IP
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
# Restore original method & URL
|
||||
proxy_set_header X-Original-Method $request_method;
|
||||
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
|
||||
|
||||
# Forward host header
|
||||
proxy_set_header Host $host;
|
||||
|
||||
# Upgrade connection
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Enable X-Forwarded headers
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
2
etc/nginx/snippets/quic.conf
Normal file
2
etc/nginx/snippets/quic.conf
Normal file
@ -0,0 +1,2 @@
|
||||
quic_retry on;
|
||||
add_header Alt-Svc 'h3=":443"; ma=86400';
|
25
etc/nginx/snippets/security.conf
Normal file
25
etc/nginx/snippets/security.conf
Normal file
@ -0,0 +1,25 @@
|
||||
# Global security headers - apply everywhere
|
||||
|
||||
# We do not set clipboard-write() here, because it is very commonly used
|
||||
proxy_hide_header Strict-Transport-Security;
|
||||
add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), bluetooth=(), browsing-topics=(), camera=(), clipboard-read=(), display-capture=(), document-domain=(), encrypted-media=(), fullscreen=(), gamepad=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), interest-cohort=(), keyboard-map=(), local-fonts=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), serial=(), speaker-selection=(), sync-xhr=(), usb=(), xr-spatial-tracking=()" always;
|
||||
|
||||
proxy_hide_header Permissions-Policy;
|
||||
add_header Referrer-Policy "same-origin" always;
|
||||
|
||||
proxy_hide_header X-Content-Type-Options;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
|
||||
proxy_hide_header X-Frame-Options;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
|
||||
proxy_hide_header Cross-Origin-Resource-Policy;
|
||||
add_header Cross-Origin-Resource-Policy cross-origin;
|
||||
|
||||
proxy_hide_header Cross-Origin-Opener-Policy;
|
||||
add_header Cross-Origin-Opener-Policy same-origin;
|
||||
|
||||
# Obsolete and replaced by Content-Security-Policy
|
||||
# Only here to pass Hardenize checks
|
||||
proxy_hide_header X-XSS-Protection;
|
||||
add_header X-XSS-Protection "0" always;
|
3
etc/nginx/snippets/universal_paths.conf
Normal file
3
etc/nginx/snippets/universal_paths.conf
Normal file
@ -0,0 +1,3 @@
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /srv/nginx;
|
||||
}
|
2
etc/sysctl.d/99-nonlocal-bind.conf
Normal file
2
etc/sysctl.d/99-nonlocal-bind.conf
Normal file
@ -0,0 +1,2 @@
|
||||
net.ipv4.ip_nonlocal_bind = 1
|
||||
net.ipv6.ip_nonlocal_bind = 1
|
30
etc/systemd/system/certbot-renew.service.d/override.conf
Normal file
30
etc/systemd/system/certbot-renew.service.d/override.conf
Normal file
@ -0,0 +1,30 @@
|
||||
# Based on https://github.com/GrapheneOS/infrastructure/blob/main/systemd/system/certbot-renew.service.d/local.conf
|
||||
|
||||
[Service]
|
||||
CapabilityBoundingSet=
|
||||
CPUSchedulingPolicy=batch
|
||||
LockPersonality=true
|
||||
MemoryDenyWriteExecute=true
|
||||
NoNewPrivileges=true
|
||||
PrivateDevices=true
|
||||
PrivateIPC=true
|
||||
PrivateUsers=true
|
||||
PrivateTmp=true
|
||||
ProcSubset=pid
|
||||
ProtectClock=true
|
||||
ProtectControlGroups=true
|
||||
ProtectHome=read-only
|
||||
ProtectHostname=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectProc=invisible
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/etc/letsencrypt /var/lib/letsencrypt /var/log/letsencrypt -/srv/nginx -/var/cache/certbot-ocsp-fetcher
|
||||
RestrictAddressFamilies=AF_INET AF_INET6
|
||||
RestrictNamespaces=true
|
||||
RestrictRealtime=true
|
||||
RestrictSUIDSGID=true
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
SystemCallFilter=~@resources @obsolete
|
30
etc/systemd/system/nginx.service.d/override.conf
Normal file
30
etc/systemd/system/nginx.service.d/override.conf
Normal file
@ -0,0 +1,30 @@
|
||||
# Based on https://github.com/GrapheneOS/infrastructure/blob/main/systemd/system/nginx.service.d/local.conf
|
||||
|
||||
[Service]
|
||||
CapabilityBoundingSet=CAP_CHOWN CAP_DAC_OVERRIDE CAP_NET_BIND_SERVICE CAP_SETUID CAP_SETGID
|
||||
LockPersonality=true
|
||||
MemoryDenyWriteExecute=true
|
||||
NoNewPrivileges=true
|
||||
PrivateDevices=true
|
||||
PrivateIPC=true
|
||||
PrivateTmp=true
|
||||
ProcSubset=pid
|
||||
ProtectClock=true
|
||||
ProtectControlGroups=true
|
||||
ProtectHome=true
|
||||
ProtectHostname=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectProc=invisible
|
||||
ProtectSystem=strict
|
||||
ReadWritePaths=/var/lib/nginx /var/log/nginx -/var/cache/nginx
|
||||
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
||||
RestrictNamespaces=true
|
||||
RestrictRealtime=true
|
||||
RestrictSUIDSGID=true
|
||||
RuntimeDirectory=nginx
|
||||
RuntimeDirectoryMode=700
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
SystemCallFilter=~@obsolete
|
85
setup.sh
Normal file
85
setup.sh
Normal file
@ -0,0 +1,85 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (C) 2024 Thien Tran
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy of
|
||||
# the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
|
||||
|
||||
# Allow reverse proxy
|
||||
sudo setsebool -P httpd_can_network_connect 1
|
||||
|
||||
# Allow QUIC
|
||||
sudp semanage port -a -t http_port_t -p udp 443
|
||||
|
||||
# Open ports for NGINX
|
||||
sudo firewall-cmd --permanent --add-service=http
|
||||
sudo firewall-cmd --permanent --add-service=https
|
||||
sudo firewall-cmd --permanent --add-port=443/udp
|
||||
sudo firewall-cmd --reload
|
||||
|
||||
# Add 99-nonlocal-bind.conf
|
||||
# This fixes a long standing bug where network-online.target is reached before IPv6 is obtained, which breaks IPv6 pinning.
|
||||
# Also, if you are using floating IPs for NGINX stream like I do, you need it anyways
|
||||
curl https://raw.githubusercontent.com/TommyTran732/NGINX-Configs/main/etc/sysctl.d/99-nonlocal-bind.conf | sudo tee /etc/sysctl.d/99-nonlocal-bind.conf
|
||||
|
||||
# Setup webroot for NGINX
|
||||
sudo mkdir /srv/nginx
|
||||
## Explicitly using /var/srv here because SELinux does not follow symlinks
|
||||
sudo semanage fcontext -a -t httpd_sys_content_t "/var/srv/nginx(/.*)?"
|
||||
sudo restorecon -Rv /var/srv/nginx
|
||||
sudo mkdir -p /srv/nginx/.well-known/acme-challenge
|
||||
|
||||
# NGINX hardening
|
||||
sudo mkdir -p /etc/systemd/system/nginx.service.d
|
||||
curl https://raw.githubusercontent.com/GrapheneOS/infrastructure/main/systemd/system/nginx.service.d/local.conf | sudo tee /etc/systemd/system/nginx.service.d/override.conf
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
# Setup certbot-ocsp-fetcher
|
||||
curl https://raw.githubusercontent.com/GrapheneOS/infrastructure/main/certbot-ocsp-fetcher | sudo tee /usr/local/bin/certbot-ocsp-fetcher
|
||||
## Explicitly using /var/usrlocal/bin here because SELinux does not follow symlinks
|
||||
sudo semanage fcontext -a -t bin_t /var/usrlocal/bin/certbot-ocsp-fetcher
|
||||
sudo restorecon -Rv /var/usrlocal/bin/certbot-ocsp-fetcher
|
||||
sudo mkdir /var/cache/certbot-ocsp-fetcher/
|
||||
sudo semanage fcontext -a -t httpd_config_t "/var/cache/certbot-ocsp-fetcher(/.*)?"
|
||||
|
||||
# Setup nginx-create-session-ticket-keys
|
||||
curl https://raw.githubusercontent.com/GrapheneOS/infrastructure/main/nginx-create-session-ticket-keys | sudo tee /usr/local/bin/nginx-create-session-ticket-keys
|
||||
## Explicitly using /var/usrlocal/bin here because SELinux does not follow symlinks
|
||||
sudo semanage fcontext -a -t bin_t /var/usrlocal/bin/nginx-create-session-ticket-keys
|
||||
sudo restorecon /var/usrlocal/bin/nginx-create-session-ticket-keys
|
||||
echo 'restorecon -Rv /etc/nginx/session-ticket-keys' | sudo tee -a /usr/local/bin/nginx-create-session-ticket-keys
|
||||
|
||||
# Setup nginx-rotate-session-ticket-keys
|
||||
curl https://raw.githubusercontent.com/GrapheneOS/infrastructure/main/nginx-rotate-session-ticket-keys | sudo tee /usr/local/bin/nginx-rotate-session-ticket-keys
|
||||
## Explicitly using /var/usrlocal/bin here because SELinux does not follow symlinks
|
||||
sudo semanage fcontext -a -t bin_t /var/usrlocal/bin/nginx-rotate-session-ticket-keys
|
||||
sudo restorecon -Rv /var/usrlocal/bin/nginx-rotate-session-ticket-keys
|
||||
sudo sed -i '$i restorecon -Rv /etc/nginx/session-ticket-keys' /var/usrlocal/bin/nginx-rotate-session-ticket-keys
|
||||
|
||||
# Download the units
|
||||
curl https://raw.githubusercontent.com/GrapheneOS/infrastructure/main/systemd/system/certbot-ocsp-fetcher.service | sudo tee /etc/systemd/system/certbot-ocsp-fetcher.service
|
||||
curl https://raw.githubusercontent.com/GrapheneOS/infrastructure/main/systemd/system/certbot-ocsp-fetcher.timer | sudo tee /etc/systemd/system/certbot-ocsp-fetcher.timer
|
||||
curl https://raw.githubusercontent.com/GrapheneOS/infrastructure/main/systemd/system/nginx-create-session-ticket-keys.service | sudo tee /etc/systemd/system/nginx-create-session-ticket-keys.service
|
||||
curl https://raw.githubusercontent.com/GrapheneOS/infrastructure/main/systemd/system/nginx-rotate-session-ticket-keys.service | sudo tee /etc/systemd/system/nginx-rotate-session-ticket-keys.service
|
||||
curl https://raw.githubusercontent.com/GrapheneOS/infrastructure/main/systemd/system/nginx-rotate-session-ticket-keys.timer | sudo tee /etc/systemd/system/nginx-rotate-session-ticket-keys.timer
|
||||
|
||||
# Systemd Hardening
|
||||
sudo mkdir -p /etc/systemd/system/nginx.service.d /etc/systemd/system/certbot-renew.service.d
|
||||
curl https://raw.githubusercontent.com/TommyTran732/NGINX-Configs/main/etc/systemd/system/nginx.service.d/override.conf | sudo tee /etc/systemd/system/nginx.service.d/override.conf
|
||||
curl https://raw.githubusercontent.com/TommyTran732/NGINX-Configs/main/etc/systemd/system/certbot-renew.service.d/override.conf | sudo tee /etc/systemd/system/certbot-renew.service.d/override.conf
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
# Enable the units
|
||||
sudo systemctl enable certbot-ocsp-fetcher.timer
|
||||
sudo systemctl enable --now nginx-create-session-ticket-keys.service
|
||||
sudo systemctl enable --now nginx-rotate-session-ticket-keys.timer
|
Loading…
x
Reference in New Issue
Block a user