diff --git a/configs/nginx/README.md b/configs/nginx/README.md new file mode 100644 index 00000000..10574a05 --- /dev/null +++ b/configs/nginx/README.md @@ -0,0 +1,3 @@ +`nginx.example` - Example nginx config with letsencrypt. You need to update with the path of installation, certificate paths, domain names, etc. +`nginx_no_https.example` - Same thing, without https. Can be used for testing and development. +`nginx_advanced.example` - An advanced example with both clearnet and tor, with snippets to reduce repitition for a cleaner config diff --git a/configs/nginx/nginx.example b/configs/nginx/nginx.example index 60c2e3ea..d9941ab6 100644 --- a/configs/nginx/nginx.example +++ b/configs/nginx/nginx.example @@ -328,7 +328,7 @@ server { # location ~* \.json$ { # expires 0; # root /path/to/jschan/static/json; -# try_files $uri =404; +# try_files $uri @backend; # #json doesnt hit backend if it doesnt exist yet. # } # diff --git a/configs/nginx/nginx_advanced.example b/configs/nginx/nginx_advanced.example new file mode 100644 index 00000000..a5fc27a7 --- /dev/null +++ b/configs/nginx/nginx_advanced.example @@ -0,0 +1,56 @@ +upstream chan { + server 127.0.0.1:7000; +} + +server { + + server_name www.xxxxxxxx.onion xxxxxxxx.onion; + + client_max_body_size 0; + listen unix:/var/run/nginx-tor.sock; + allow "unix:"; + deny all; + + include /etc/nginx/snippets/security_headers.conf; + include /etc/nginx/snippets/error_pages.conf; + include /etc/nginx/snippets/jschan_routes_tor.conf; + +} + +server { + + server_name www.example.com example.com; + + client_max_body_size 0; + #header will tell tor users accessing clearnet endpoint to use onion service + add_header onion-location 'http://xxxxxxxxxxx.onion'; + + include /etc/nginx/snippets/security_headers.conf; + include /etc/nginx/snippets/error_pages.conf; + include /etc/nginx/snippets/jschan_routes.conf; + + listen [::]:443 ssl ipv6only=on; # managed by Certbot + listen 443 ssl; # managed by Certbot + ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot + include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot + +} + +server { + if ($host = www.example.com) { + return 301 https://$host$request_uri; + } # managed by Certbot + + if ($host = example.com) { + return 301 https://$host$request_uri; + } # managed by Certbot + + server_name www.example.com example.com; + + listen 80; + listen [::]:80; + return 444; # managed by Certbot + +} diff --git a/configs/nginx/snippets/jschan_routes.conf b/configs/nginx/snippets/jschan_routes.conf index 1204e5d3..a2b4ba9d 100644 --- a/configs/nginx/snippets/jschan_routes.conf +++ b/configs/nginx/snippets/jschan_routes.conf @@ -4,14 +4,12 @@ if ($request_uri ~ ^/(?!captcha|randombanner|forms|logout|socket\.io)) { } location = /robots.txt { - testcookie off; access_log off; add_header Content-Type text/plain; return 200 "User-agent: *\nDisallow:\n"; } location = /site.webmanifest { - testcookie off; access_log off; expires max; root /path/to/jschan/static/file; @@ -19,7 +17,6 @@ location = /site.webmanifest { } location = /browserconfig.xml { - testcookie off; access_log off; expires max; root /path/to/jschan/static/file; @@ -27,7 +24,6 @@ location = /browserconfig.xml { } location = /favicon.ico { - testcookie off; access_log off; expires max; root /path/to/jschan/static/file; @@ -35,13 +31,13 @@ location = /favicon.ico { } location = / { - return 302 http://$host/index.html; + return 302 https://$host/index.html; } location /captcha { root /path/to/jschan/static/captcha; if ($cookie_captchaid) { - return 302 http://$host/captcha/$cookie_captchaid.jpg; + return 302 https://$host/captcha/$cookie_captchaid.jpg; } try_files /$cookie_captchaid.jpg @backend; } @@ -56,20 +52,20 @@ location / { proxy_set_header Connection 'upgrade'; proxy_cache_bypass $http_upgrade; - proxy_set_header X-Forwarded-Proto http; + proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Country-Code 'TOR'; + proxy_set_header X-Country-Code $geoip_country_code; } location @backend { proxy_buffering off; proxy_pass http://chan$request_uri; proxy_http_version 1.1; - proxy_set_header X-Forwarded-Proto http; + proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Country-Code 'TOR'; + proxy_set_header X-Country-Code $geoip_country_code; proxy_set_header Connection ''; proxy_set_header Host $host; } @@ -84,15 +80,14 @@ location ~* \.html$ { # JSON location ~* \.json$ { - testcookie off; expires 0; root /path/to/jschan/static/json; try_files $uri @backend; + #json doesnt hit backend if it doesnt exist yet. } # CSS location ~* \.css$ { - testcookie off; access_log off; expires 1w; root /path/to/jschan/static; @@ -101,7 +96,6 @@ location ~* \.css$ { # Scripts location ~* \.js$ { - testcookie off; expires 1w; access_log off; root /path/to/jschan/static; @@ -110,7 +104,6 @@ location ~* \.js$ { # Files (image, video, audio, other) location ~* \.(png|jpg|jpeg|webmanifest|apng|bmp|webp|pjpeg|jfif|gif|mp4|webm|mov|mkv|svg|mp3|ogg|wav|opus)$ { - testcookie off; access_log off; expires max; root /path/to/jschan/static; @@ -118,8 +111,7 @@ location ~* \.(png|jpg|jpeg|webmanifest|apng|bmp|webp|pjpeg|jfif|gif|mp4|webm|mo } # inline in browser so even HTML filetypes can be offered and will present a "save" dialog box -location ~* \.(txt)$ { - testcookie off; +location ~* \.(txt|bin)$ { access_log off; expires max; add_header Cache-Control "public"; diff --git a/configs/nginx/snippets/jschan_routes_tor.conf b/configs/nginx/snippets/jschan_routes_tor.conf new file mode 100644 index 00000000..c224a2a9 --- /dev/null +++ b/configs/nginx/snippets/jschan_routes_tor.conf @@ -0,0 +1,122 @@ +if ($request_uri ~ ^/(?!captcha|randombanner|forms|logout|socket\.io)) { + rewrite ^([^.\?]*[^/])$ $1/ redirect; + rewrite ^(.+)/$ $1/index.html redirect; +} + +location = /robots.txt { + access_log off; + add_header Content-Type text/plain; + return 200 "User-agent: *\nDisallow:\n"; +} + +location = /site.webmanifest { + access_log off; + expires max; + root /path/to/jschan/static/file; + try_files $uri =404; +} + +location = /browserconfig.xml { + access_log off; + expires max; + root /path/to/jschan/static/file; + try_files $uri =404; +} + +location = /favicon.ico { + access_log off; + expires max; + root /path/to/jschan/static/file; + try_files $uri =404; +} + +location = / { + return 302 http://$host/index.html; +} + +location /captcha { + root /path/to/jschan/static/captcha; + if ($cookie_captchaid) { + return 302 http://$host/captcha/$cookie_captchaid.jpg; + } + try_files /$cookie_captchaid.jpg @backend; +} + +location / { + proxy_buffering off; + proxy_pass http://chan$request_uri; + proxy_http_version 1.1; + + proxy_set_header Host $host; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_cache_bypass $http_upgrade; + + proxy_set_header X-Forwarded-Proto http; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Country-Code 'TOR'; +} + +location @backend { + proxy_buffering off; + proxy_pass http://chan$request_uri; + proxy_http_version 1.1; + proxy_set_header X-Forwarded-Proto http; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Country-Code 'TOR'; + proxy_set_header Connection ''; + proxy_set_header Host $host; +} + +# HTML +location ~* \.html$ { + expires 0; + default_type text/html; #needed for cache control private in backend + root /path/to/jschan/static/html; + try_files $uri @backend; +} + +# JSON +location ~* \.json$ { + expires 0; + root /path/to/jschan/static/json; + try_files $uri @backend; + #json doesnt hit backend if it doesnt exist yet. +} + +# CSS +location ~* \.css$ { + access_log off; + expires 1w; + root /path/to/jschan/static; + try_files $uri =404; +} + +# Scripts +location ~* \.js$ { + expires 1w; + access_log off; + root /path/to/jschan/static; + try_files $uri =404; +} + +# Files (image, video, audio, other) +location ~* \.(png|jpg|jpeg|webmanifest|apng|bmp|webp|pjpeg|jfif|gif|mp4|webm|mov|mkv|svg|mp3|ogg|wav|opus)$ { + access_log off; + expires max; + root /path/to/jschan/static; + try_files $uri =404; +} + +# inline in browser so even HTML filetypes can be offered and will present a "save" dialog box +location ~* \.(txt|bin)$ { + access_log off; + expires max; + add_header Cache-Control "public"; + add_header X-Content-Type-Options "nosniff" always; + add_header Content-Disposition "attachment"; + root /path/to/jschan/static; + try_files $uri =404; +}