diff --git a/roles/archwiki/files/nginx-cache-purge b/roles/archwiki/files/nginx-cache-purge new file mode 100644 index 0000000000000000000000000000000000000000..d1bc7262eeec17786617028a6cc33fd318b59d05 --- /dev/null +++ b/roles/archwiki/files/nginx-cache-purge @@ -0,0 +1,30 @@ +#!/usr/bin/env python +import hashlib +import http.server +import pathlib +import socketserver +import urllib.parse + +socketserver.ThreadingTCPServer.allow_reuse_address = True + + +class Handler(http.server.BaseHTTPRequestHandler): + def do_PURGE(self): + self.send_response(http.HTTPStatus.OK) + self.end_headers() + o = urllib.parse.urlparse(self.path) + for method in ["GET", "HEAD"]: + # Please keep in sync with "fastcgi_cache_key" in nginx.d.conf.j2 + if o.query: + cache_key = f"https{method}{o.netloc}{o.path}?{o.query}" + else: + cache_key = f"https{method}{o.netloc}{o.path}" + hash = hashlib.md5(cache_key.encode("utf-8")).hexdigest() + # Please keep in sync with "fastcgi_cache_path" in nginx.d.conf.j2 + pathlib.Path( + f"/var/lib/nginx/cache/{hash[-1]}/{hash[-3:-1]}/{hash}" + ).unlink(missing_ok=True) + + +httpd = http.server.ThreadingHTTPServer(("127.0.0.1", 1080), Handler) +httpd.serve_forever() diff --git a/roles/archwiki/tasks/main.yml b/roles/archwiki/tasks/main.yml index 9140317c71e77a078cf0c94e0184de3d2ae2c486..789cb15173d750726a9f03dc9d3724d79f585a8c 100644 --- a/roles/archwiki/tasks/main.yml +++ b/roles/archwiki/tasks/main.yml @@ -97,16 +97,18 @@ - name: Start and enable memcached service systemd: name=memcached@archwiki.service state=started enabled=true daemon_reload=true +- name: Install nginx-cache-purge script + copy: src=nginx-cache-purge dest=/usr/local/bin/nginx-cache-purge owner=root group=root mode=0755 + - name: Install systemd services/timers template: src="{{ item }}.j2" dest="/etc/systemd/system/{{ item }}" owner=root group=root mode=0644 loop: - archwiki-runjobs.service - archwiki-runjobs-wait.service - archwiki-runjobs.timer - - archwiki-prune-cache.service - - archwiki-prune-cache.timer - archwiki-question-updater.service - archwiki-question-updater.timer + - nginx-cache-purge.service - name: Start and enable archwiki timers and services systemd: @@ -116,9 +118,9 @@ daemon_reload: true with_items: - archwiki-runjobs.timer - - archwiki-prune-cache.timer - archwiki-runjobs-wait.service - archwiki-question-updater.timer + - nginx-cache-purge.service - name: Create question answer file systemd: diff --git a/roles/archwiki/templates/LocalSettings.php.j2 b/roles/archwiki/templates/LocalSettings.php.j2 index 70b55bb3dca2d28cacf895476b62fdbc615f85d0..d5b049494b144e2dcc92c4743bbdda85cfbc15f6 100644 --- a/roles/archwiki/templates/LocalSettings.php.j2 +++ b/roles/archwiki/templates/LocalSettings.php.j2 @@ -147,9 +147,9 @@ $wgMemCachedServers = [ "unix://{{ archwiki_memcached_socket }}" ]; ## be publicly accessible from the web. $wgCacheDirectory = "$IP/../cache/data"; $wgEnableSidebarCache = true; -$wgUseFileCache = true; -$wgFileCacheDirectory = "$IP/../cache/html"; -$wgUseGzip = true; +$wgUseCdn = true; +$wgCdnServers = [ '127.0.0.1' ]; +$wgInternalServer = 'http://wiki.archlinux.org'; # CSS-based preferences supposedly cause about 20 times slower page loads # https://phabricator.wikimedia.org/rSVN63707 diff --git a/roles/archwiki/templates/archwiki-prune-cache.service.j2 b/roles/archwiki/templates/archwiki-prune-cache.service.j2 deleted file mode 100644 index 458800531d39d525f1aa6ea23bfc038b0ec3f2c4..0000000000000000000000000000000000000000 --- a/roles/archwiki/templates/archwiki-prune-cache.service.j2 +++ /dev/null @@ -1,21 +0,0 @@ -[Unit] -Description=Archwiki Prune Cache Service - -[Service] -Type=oneshot -User={{ archwiki_user }} -WorkingDirectory={{ archwiki_dir }} -ExecStart=/usr/bin/php {{ archwiki_dir }}/public/maintenance/run.php pruneFileCache -q --agedays 1 - -NoNewPrivileges=yes -PrivateTmp=yes -PrivateDevices=yes -PrivateNetwork=true -ProtectSystem=full -ProtectHome=true -ProtectControlGroups=yes -ProtectKernelModules=yes -ProtectKernelTunables=yes - -[Install] -WantedBy=multi-user.target diff --git a/roles/archwiki/templates/archwiki-prune-cache.timer.j2 b/roles/archwiki/templates/archwiki-prune-cache.timer.j2 deleted file mode 100644 index 95200a1904d20b83e35dd4a52e9ea694387e1024..0000000000000000000000000000000000000000 --- a/roles/archwiki/templates/archwiki-prune-cache.timer.j2 +++ /dev/null @@ -1,8 +0,0 @@ -[Unit] -Description=Archwiki Prune Cache timer - -[Timer] -OnCalendar=*-*-* 04:12:00 - -[Install] -WantedBy=timers.target diff --git a/roles/archwiki/templates/nginx-cache-purge.service.j2 b/roles/archwiki/templates/nginx-cache-purge.service.j2 new file mode 100644 index 0000000000000000000000000000000000000000..a8d619fecca7cc21a1698862d1e25eb3ced755b9 --- /dev/null +++ b/roles/archwiki/templates/nginx-cache-purge.service.j2 @@ -0,0 +1,11 @@ +[Unit] +Description=nginx cache PURGE service + +[Service] +User=http +ProtectSystem=strict +ReadWritePaths=/var/lib/nginx/cache +ExecStart=/usr/local/bin/nginx-cache-purge + +[Install] +WantedBy=multi-user.target diff --git a/roles/archwiki/templates/nginx.d.conf.j2 b/roles/archwiki/templates/nginx.d.conf.j2 index 86bc74263b712fbdcbaa89f299c293eecd553399..e83eab7f95acd48d382d5d066b3978e508301967 100644 --- a/roles/archwiki/templates/nginx.d.conf.j2 +++ b/roles/archwiki/templates/nginx.d.conf.j2 @@ -1,4 +1,6 @@ -fastcgi_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=wiki:100m inactive=60m; +# 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 @@ -110,10 +112,18 @@ server { fastcgi_index index.php; include fastcgi.conf; +{% block wiki_cache %} fastcgi_cache wiki; - fastcgi_cache_valid 200 10m; + # 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 servce. + # [1] https://www.fastly.com/blog/best-practices-using-vary-header/ + # [2] https://github.com/nginx/nginx/commit/1332e76b20a6a1e871904525d42b17dcaed81eec + fastcgi_ignore_headers Vary; add_header X-Cache $upstream_cache_status; +{% endblock %} } # mediawiki API endpoint @@ -141,6 +151,11 @@ server { 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; }