mirror of
https://gitlab.archlinux.org/archlinux/infrastructure.git
synced 2025-01-18 08:06:16 +01:00
We want to roll out HTTP/3 slowly, so this adds the necessary plumbing and makes it possible to enable it per host. Instead of adding the conditional logic to each nginx template, the 443 listen config is moved out into a snippet which is managed by the nginx role. HTTP/3 uses QUIC which is built on UDP. UDP is connectionless and therefore reuseport[1][2] must be used to ensure that UDP packets for the same QUIC connection is directed to the same worker. reuseport can only be enabled once, so a default_server is added to the "inventory_hostname vhost" for SSL/QUIC (reuseport is only enabled for the latter). ssl_reject_handshake[3] is enabled as that allows enabling SSL/QUIC without specifying a certificate. [1] https://nginx.org/en/docs/http/ngx_http_core_module.html#listen [2] https://lwn.net/Articles/542629/ [3] http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_reject_handshake Ref #606
190 lines
6.3 KiB
Django/Jinja
190 lines
6.3 KiB
Django/Jinja
# Please keep "path" and "levels" in sync with nginx-cache-purge
|
|
fastcgi_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=wiki:100m inactive=720m;
|
|
# Please keep in sync with "cache_key" in nginx-cache-purge
|
|
fastcgi_cache_key "$scheme$request_method$host$request_uri";
|
|
|
|
# rate limit API endpoint
|
|
limit_req_zone $binary_remote_addr zone=api_zone:10m rate=5r/s;
|
|
|
|
# limit general requests to 10 r/s to block DoS attempts with a burst of 10.
|
|
limit_req_zone $binary_remote_addr zone=archwikilimit:10m rate=10r/s;
|
|
|
|
limit_req_status 429;
|
|
|
|
upstream archwiki {
|
|
server unix://{{ archwiki_socket }};
|
|
}
|
|
|
|
# Challenge the client if the cookie "challenge" is not set to
|
|
# the value of "archwiki_nginx_challenge_value".
|
|
map $cookie_challenge $challenge_required2 {
|
|
default 1;
|
|
{{ archwiki_nginx_challenge_value }} 0;
|
|
}
|
|
|
|
# Challenge the client if it is requesting an "action view" and
|
|
# $challenge_required2 is true.
|
|
map $request_uri $challenge_required {
|
|
default 0;
|
|
~^/index\.php\? $challenge_required2;
|
|
}
|
|
|
|
geoip2 /var/lib/GeoIP/GeoLite2-Country.mmdb {
|
|
auto_reload 60m;
|
|
$geoip2_data_country_iso_code country iso_code;
|
|
}
|
|
|
|
# Challenge the client if it is from China and $challenge_required is
|
|
# true. This is enough to "throw off" some bots/crawlers from China.
|
|
map $geoip2_data_country_iso_code $challenge {
|
|
default 0;
|
|
CN $challenge_required;
|
|
}
|
|
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name {{ archwiki_domain }};
|
|
|
|
access_log /var/log/nginx/{{ archwiki_domain }}/access.log reduced;
|
|
access_log /var/log/nginx/{{ archwiki_domain }}/access.log.json json_reduced;
|
|
error_log /var/log/nginx/{{ archwiki_domain }}/error.log;
|
|
|
|
include snippets/letsencrypt.conf;
|
|
|
|
location / {
|
|
access_log off;
|
|
return 301 https://$server_name$request_uri;
|
|
}
|
|
}
|
|
|
|
server {
|
|
include snippets/listen-443.conf;
|
|
server_name {{ archwiki_domain }};
|
|
|
|
access_log /var/log/nginx/{{ archwiki_domain }}/access.log reduced;
|
|
access_log /var/log/nginx/{{ archwiki_domain }}/access.log.json json_reduced;
|
|
error_log /var/log/nginx/{{ archwiki_domain }}/error.log;
|
|
|
|
ssl_certificate /etc/letsencrypt/live/{{ archwiki_domain }}/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/{{ archwiki_domain }}/privkey.pem;
|
|
ssl_trusted_certificate /etc/letsencrypt/live/{{ archwiki_domain }}/chain.pem;
|
|
|
|
root {{ archwiki_dir }}/public;
|
|
index index.php;
|
|
|
|
# Block search bot that apparently never heared the term rate limiting
|
|
if ($http_user_agent ~ "Bytespider$" ) {
|
|
return 403;
|
|
}
|
|
|
|
location = /robots.txt {
|
|
alias {{ archwiki_dir }}/robots.txt;
|
|
}
|
|
|
|
location ^~ /. {
|
|
log_not_found off;
|
|
deny all;
|
|
}
|
|
|
|
# Redirect old URLs to the new short-url (/title/<page>)
|
|
location ~ ^/index.php/(.*)$ {
|
|
return 301 /title/$1$is_args$args;
|
|
}
|
|
|
|
# Handling for the article path (pretty URLs)
|
|
location ^~ /title/ {
|
|
rewrite ^ /index.php;
|
|
}
|
|
|
|
# Handling for MediaWiki REST API, see https://www.mediawiki.org/wiki/API:REST_API
|
|
location ^~ /rest.php/ {
|
|
rewrite ^ /rest.php;
|
|
}
|
|
|
|
# special case for '/load.php' type URLs to cache css/js in nginx to relieve php-fpm
|
|
location = /load.php {
|
|
access_log /var/log/nginx/{{ archwiki_domain }}/access.log main;
|
|
access_log /var/log/nginx/{{ archwiki_domain }}/access.log.json json_main;
|
|
fastcgi_pass archwiki;
|
|
fastcgi_index index.php;
|
|
include fastcgi.conf;
|
|
|
|
{% block wiki_cache %}
|
|
fastcgi_cache wiki;
|
|
# This improves the cache hit ratio[1] and ensures that there is
|
|
# only a single cache file. Without this, nginx will use the
|
|
# Vary header as an secondary cache key[2], which breaks the
|
|
# cache purge service.
|
|
# [1] https://www.fastly.com/blog/best-practices-using-vary-header/
|
|
# [2] https://github.com/nginx/nginx/commit/1332e76b20a6a1e871904525d42b17dcaed81eec
|
|
fastcgi_ignore_headers Vary;
|
|
fastcgi_cache_background_update on;
|
|
fastcgi_cache_use_stale updating;
|
|
fastcgi_cache_lock on;
|
|
|
|
include snippets/headers.conf;
|
|
add_header X-Cache $upstream_cache_status;
|
|
{% endblock %}
|
|
}
|
|
|
|
# mediawiki API endpoint
|
|
location ~ ^/api\.php {
|
|
limit_req zone=api_zone burst=10 delay=5;
|
|
try_files $uri =404;
|
|
access_log /var/log/nginx/{{ archwiki_domain }}/access.log main;
|
|
access_log /var/log/nginx/{{ archwiki_domain }}/access.log.json json_main;
|
|
fastcgi_pass archwiki;
|
|
fastcgi_index index.php;
|
|
include fastcgi.conf;
|
|
}
|
|
|
|
# normal PHP FastCGI handler
|
|
location ~ ^/[^/]+\.php$ {
|
|
if ($challenge) {
|
|
include snippets/headers.conf;
|
|
add_header Set-Cookie "challenge={{ archwiki_nginx_challenge_value }}; SameSite=Strict";
|
|
return 303 $scheme://$server_name/$request_uri;
|
|
}
|
|
|
|
try_files $uri =404;
|
|
access_log /var/log/nginx/{{ archwiki_domain }}/access.log main;
|
|
access_log /var/log/nginx/{{ archwiki_domain }}/access.log.json json_main;
|
|
fastcgi_pass archwiki;
|
|
fastcgi_index index.php;
|
|
include fastcgi.conf;
|
|
|
|
{{ self.wiki_cache() }}
|
|
# https://www.mediawiki.org/w/index.php?title=Manual:Varnish_caching&oldid=6230975#Configuring_Varnish
|
|
fastcgi_cache_bypass $http_authorization $cookie_archwiki_session $cookie_archwikiToken;
|
|
fastcgi_no_cache $http_authorization $cookie_archwiki_session $cookie_archwikiToken;
|
|
|
|
limit_req zone=archwikilimit burst=10 nodelay;
|
|
}
|
|
|
|
# MediaWiki assets
|
|
location ~ ^/(?:images|resources/(?:assets|lib|src)|(?:skins|extensions)/.+\.(?:css|js|gif|jpg|jpeg|png|svg|wasm)$) {
|
|
expires 30d;
|
|
include snippets/headers.conf;
|
|
add_header Pragma public;
|
|
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
|
|
}
|
|
|
|
location /images/ {
|
|
# Add the nosniff header to the images folder (required for mw 1.40+)
|
|
include snippets/headers.conf;
|
|
add_header X-Content-Type-Options nosniff;
|
|
}
|
|
|
|
location /images/deleted {
|
|
# Deny access to deleted images folder
|
|
deny all;
|
|
}
|
|
|
|
# block all other directories
|
|
location ~ ^/[^/]+/ {
|
|
log_not_found off;
|
|
deny all;
|
|
}
|
|
}
|