summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nginx/server.conf121
-rw-r--r--nginx/snippets/security-headers.conf9
2 files changed, 130 insertions, 0 deletions
diff --git a/nginx/server.conf b/nginx/server.conf
new file mode 100644
index 00000000..fee40bbc
--- /dev/null
+++ b/nginx/server.conf
@@ -0,0 +1,121 @@
+server {
+ listen 80;
+ listen [::]:80;
+
+ server_name connectivitycheck.grapheneos.org www.grapheneos.org grapheneos.org;
+
+ root /var/empty;
+
+ return 301 https://grapheneos.org$request_uri;
+}
+
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+
+ server_name connectivitycheck.grapheneos.org www.grapheneos.org grapheneos.org;
+
+ root /var/www/html;
+
+ ssl_certificate /etc/letsencrypt/live/grapheneos.org/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/grapheneos.org/privkey.pem;
+ include /etc/letsencrypt/options-ssl-nginx.conf;
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
+
+ ssl_trusted_certificate /etc/letsencrypt/live/grapheneos.org/chain.pem;
+ ssl_stapling on;
+ ssl_stapling_verify on;
+
+ if ($host != "grapheneos.org") {
+ return 301 https://grapheneos.org$request_uri;
+ }
+
+ if ($request_uri ~ ^/(.*)\.html$) {
+ return 301 /$1;
+ }
+
+ if ($request_uri ~ ^(.*)/index$) {
+ return 301 $1/;
+ }
+
+ location = /security.txt {
+ return 301 /.well-known/security.txt;
+ }
+
+ location = /graphene.png {
+ return 301 /logo.png;
+ }
+
+ location = /pdfviewer_privacy_policy {
+ return 301 /pdfviewer-privacy-policy;
+ }
+
+ location = /safari_pinned_tab_icon.svg {
+ return 301 /mask-icon.svg;
+ }
+
+ location = /safari-pinned-tab-icon.svg {
+ return 301 /mask-icon.svg;
+ }
+
+ location = /bitcoin_address.png {
+ return 301 /bitcoin-address.png;
+ }
+
+ location = /generate_204 {
+ return 204;
+ }
+
+ location = /LICENSE {
+ default_type text/plain;
+ }
+
+ location ~ "\.(html|txt|xml)$" {
+ include /etc/nginx/snippets/security-headers.conf;
+ add_header Cache-Control "public, max-age=1800";
+ }
+
+ location ~ "\.(ico|webmanifest)$" {
+ include /etc/nginx/snippets/security-headers.conf;
+ add_header Cache-Control "public, max-age=604800";
+ }
+
+ location ~ "\.(css|js|png|svg|woff2)$" {
+ include /etc/nginx/snippets/security-headers.conf;
+ add_header Cache-Control "public, max-age=31536000";
+ }
+
+ try_files $uri $uri.html $uri/ =404;
+ include /etc/nginx/snippets/security-headers.conf;
+}
+
+server {
+ listen 80;
+ listen [::]:80;
+
+ server_name mta-sts.grapheneos.org;
+
+ root /var/empty;
+
+ return 301 https://mta-sts.grapheneos.org$request_uri;
+}
+
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+
+ server_name mta-sts.grapheneos.org;
+
+ root /var/www/mta-sts;
+
+ ssl_certificate /etc/letsencrypt/live/grapheneos.org/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/grapheneos.org/privkey.pem;
+ include /etc/letsencrypt/options-ssl-nginx.conf;
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
+
+ ssl_trusted_certificate /etc/letsencrypt/live/grapheneos.org/chain.pem;
+ ssl_stapling on;
+ ssl_stapling_verify on;
+
+ include /etc/nginx/snippets/security-headers.conf;
+}
diff --git a/nginx/snippets/security-headers.conf b/nginx/snippets/security-headers.conf
new file mode 100644
index 00000000..06243ef5
--- /dev/null
+++ b/nginx/snippets/security-headers.conf
@@ -0,0 +1,9 @@
+add_header X-XSS-Protection "1; mode=block" always;
+add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
+add_header X-Content-Type-Options "nosniff" always;
+add_header X-Frame-Options "DENY" always;
+add_header Referrer-Policy "no-referrer" always;
+add_header Expect-CT "enforce, max-age=63072000, report-uri=\"https://danielmicay.report-uri.com/r/d/ct/enforce\"" always;
+add_header Public-Key-Pins "max-age=2592000; pin-sha256=\"YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=\"; pin-sha256=\"sRHdihwgkaib1P1gxX8HFszlD+7/gTfNvuAybgLPNis=\"; pin-sha256=\"Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=\"; pin-sha256=\"C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=\"; pin-sha256=\"mABt36m6Z2G6pnosx0K3dhXY+nUrZeZVWZlSW4GBZGs=\"; pin-sha256=\"v/9edLATMEdwyTJp0eXTft119lGXjZThpGSeX7t5Jv8=\"; pin-sha256=\"+f4CIotdnI56+v8CTfQvN88mYlQ1saQ1U68YvAwlotU=\"; pin-sha256=\"q3TMLLQkHOLGnFXKL1RytMd1Vr906gdK/ymgcBnk144=\"; pin-sha256=\"x3i8R25x59RNyo1LAunh4lGFvnIYXT5oTq2dOVgxTWU=\"; includeSubDomains; report-uri=\"https://danielmicay.report-uri.com/r/d/hpkp/enforce\"" always;
+add_header Content-Security-Policy "default-src 'none'; connect-src 'self' https://releases.grapheneos.org/; font-src 'self'; img-src 'self'; manifest-src 'self'; script-src 'self'; style-src 'self'; form-action 'none'; frame-ancestors 'none'; block-all-mixed-content; base-uri 'none'; report-uri https://danielmicay.report-uri.com/r/d/csp/enforce" always;
+add_header Feature-Policy "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; battery 'none'; camera 'none'; display-capture 'none'; document-domain 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; sync-xhr 'none'; usb 'none'; wake-lock 'none'; xr-spatial-tracking 'none'" always;