(define-module (rekahsoft guix-config vms guix-ci0-home-rekahsoft-ca) #:use-module (gnu) #:use-module (gnu system) #:use-module (gnu packages shells) #:use-module (gnu services base) #:use-module (gnu services cuirass) #:use-module (gnu services web) #:use-module (rekahsoft guix-config proxmox-vm-lvm-minimal) #:export (system)) (define base-system (proxmox-vm-lvm-minimal "guix-ci0")) (define %cuirass-specs #~(let ((rekahsoft-guix-channel (channel (name 'rekahsoft-guix) (url "https://git.rekahsoft.ca/rekahsoft/rekahsoft-guix.git")))) (list (specification (name "rekahsoft-guix") (priority 0) (build '(channels rekahsoft-guix)) (channels (cons rekahsoft-guix-channel %default-channels))) (specification (name "rekahsoft-dotfiles") (build '(manifests "home-manifest.scm")) (channels (cons* (channel (name 'rekahsoft-dotfiles) (url "https://git.home.rekahsoft.ca/rekahsoft-public/dotfiles.git")) (channel (name 'nonguix) (url "https://gitlab.com/nonguix/nonguix")) rekahsoft-guix-channel %default-channels)))))) ;; Taken from: https://git.savannah.gnu.org/cgit/guix/maintenance.git/tree/hydra/nginx/berlin.scm (define (publish-locations url) "Return the nginx location blocks for 'guix publish' running on URL." (list (nginx-location-configuration (uri "/nix-cache-info") (body (list (string-append "proxy_pass " url "/nix-cache-info;") ;; Cache this file since that's always the first thing we ask ;; for. "proxy_cache static;" "proxy_cache_valid 200 100d;" ; cache hits for a looong time. "proxy_cache_valid any 5m;" ; cache misses/others for 5 min. "proxy_ignore_client_abort on;" ;; We need to hide and ignore the Set-Cookie header to enable ;; caching. "proxy_hide_header Set-Cookie;" "proxy_ignore_headers Set-Cookie;"))) (nginx-location-configuration (uri "/nar/") (body (list (string-append "proxy_pass " url ";") "client_body_buffer_size 256k;" ;; Be more tolerant of delays when fetching a nar. "proxy_read_timeout 60s;" "proxy_send_timeout 60s;" ;; Enable caching for nar files, to avoid reconstructing and ;; recompressing archives. "proxy_cache nar;" "proxy_cache_valid 200 30d;" ; cache hits for 1 month "proxy_cache_valid 504 3m;" ; timeout, when hydra.gnu.org is overloaded "proxy_cache_valid any 1h;" ; cache misses/others for 1h. "proxy_ignore_client_abort on;" ;; Nars are already compressed. "gzip off;" ;; We need to hide and ignore the Set-Cookie header to enable ;; caching. "proxy_hide_header Set-Cookie;" "proxy_ignore_headers Set-Cookie;" ;; Provide a 'content-length' header so that 'guix ;; substitute-binary' knows upfront how much it is downloading. ;; "add_header Content-Length $body_bytes_sent;" ))) (nginx-location-configuration (uri "~ \\.narinfo$") (body (list ;; Since 'guix publish' has its own caching, and since it relies ;; on the atime of cached narinfos to determine whether a ;; narinfo can be removed from the cache, don't do any caching ;; here. (string-append "proxy_pass " url ";") ;; For HTTP pipelining. This has a dramatic impact on ;; performance. "client_body_buffer_size 128k;" ;; Narinfos requests are short, serve many of them on a ;; connection. "keepalive_requests 600;" ;; Do not tolerate slowness of hydra.gnu.org when fetching ;; narinfos: better return 504 quickly than wait forever. "proxy_connect_timeout 10s;" "proxy_read_timeout 10s;" "proxy_send_timeout 10s;" ;; 'guix publish --ttl' produces a 'Cache-Control' header for ;; use by 'guix substitute'. Let it through rather than use ;; nginx's "expire" directive since the expiration time defined ;; by 'guix publish' is the right one. "proxy_pass_header Cache-Control;" "proxy_ignore_client_abort on;" ;; We need to hide and ignore the Set-Cookie header to enable ;; caching. "proxy_hide_header Set-Cookie;" "proxy_ignore_headers Set-Cookie;"))) ;; Content-addressed files served by 'guix publish'. (nginx-location-configuration (uri "/file/") (body (list (string-append "proxy_pass " url ";") "proxy_cache cas;" "proxy_cache_valid 200 200d;" ; cache hits "proxy_cache_valid any 5m;" ; cache misses/others "proxy_ignore_client_abort on;"))))) (define %publish-url "http://localhost:3000") ;; Modified from: https://git.savannah.gnu.org/cgit/guix/maintenance.git/tree/hydra/nginx/berlin.scm (berlin-locations) (define (nginx-locations publish-url) "Return nginx location blocks with 'guix publish' reachable at PUBLISH-URL." (append (publish-locations publish-url) (list ;; Cuirass. (nginx-location-configuration (uri "/") (body (list "proxy_pass http://localhost:8081;"))) ;; TODO: disabled as currently there is no auth setup for cuirass ;; (nginx-location-configuration ;; (uri "~ ^/admin") ;; (body ;; (list "if ($ssl_client_verify != SUCCESS) { return 403; } proxy_pass http://localhost:8081;"))) (nginx-location-configuration (uri "/static") (body (list "proxy_pass http://localhost:8081;" ;; Let browsers cache this for a while. "expires 10d;" ;; Cache quite aggressively. "proxy_cache static;" "proxy_cache_valid 200 5d;" "proxy_cache_valid any 10m;" "proxy_ignore_client_abort on;")))))) (define %extra-content (list "default_type application/octet-stream;" "sendfile on;" ; (accept-languages) ;; Maximum chunk size to send. Partly this is a workaround for ;; , but also the nginx docs mention that ;; "Without the limit, one fast connection may seize the worker ;; process entirely." ;; "sendfile_max_chunk 1m;" "keepalive_timeout 65;" ;; Use HTTP 1.1 to talk to the backend so we benefit from keep-alive ;; connections and chunked transfer encoding. The latter allows us to ;; make sure we do not cache partial downloads. "proxy_http_version 1.1;" ;; The 'inactive' parameter for caching is not very useful in our ;; case: all that matters is that LRU sweeping happens when 'max_size' ;; is hit. ;; cache for nar files "proxy_cache_path /var/cache/nginx/nar" " levels=2" " inactive=8d" ; inactive keys removed after 8d " keys_zone=nar:4m" ; nar cache meta data: ~32K keys " max_size=10g;" ; total cache data size max ;; cache for content-addressed files "proxy_cache_path /var/cache/nginx/cas" " levels=2" " inactive=180d" ; inactive keys removed after 180d " keys_zone=cas:8m" ; nar cache meta data: ~64K keys " max_size=50g;" ; total cache data size max ;; cache for build logs "proxy_cache_path /var/cache/nginx/logs" " levels=2" " inactive=60d" ; inactive keys removed after 60d " keys_zone=logs:8m" ; narinfo meta data: ~64K keys " max_size=4g;" ; total cache data size max ;; cache for static data "proxy_cache_path /var/cache/nginx/static" " levels=1" " inactive=10d" ; inactive keys removed after 10d " keys_zone=static:1m" ; nar cache meta data: ~8K keys " max_size=200m;" ; total cache data size max ;; If Hydra cannot honor these delays, then something is wrong and ;; we'd better drop the connection and return 504. "proxy_connect_timeout 10s;" "proxy_read_timeout 10s;" "proxy_send_timeout 10s;" ;; Cache timeouts for a little while to avoid increasing pressure. "proxy_cache_valid 504 30s;")) (define %nginx-configuration (nginx-configuration (server-blocks (list (nginx-server-configuration (listen '("80")) (server-name '("guix-ci0.home.rekahsoft.ca" "guix-ci.home.rekahsoft.ca" ;; "~[0-9]$")) (locations (nginx-locations %publish-url)) (raw-content (list "access_log /var/log/nginx/http.access.log;" "proxy_set_header X-Forwarded-Host $host;" "proxy_set_header X-Forwarded-Port $server_port;" "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;"))))) (global-directives '((worker_processes . 4) (pcre_jit . on) (events . ((worker_connections . 1024))))) (extra-content (string-join %extra-content "\n")))) (define %nginx-cache-activation ;; Make sure /var/cache/nginx exists on the first run. (simple-service 'nginx-/var/cache/nginx activation-service-type (with-imported-modules '((guix build utils)) #~(begin (use-modules (guix build utils)) (mkdir-p "/var/cache/nginx"))))) (define system (operating-system (inherit base-system) (users (cons* (user-account (name "collin") (comment "Master User") (group "users") (shell #~(string-append #$zsh "/bin/zsh")) (supplementary-groups '("wheel" "netdev" "audio" "video")) (home-directory "/home/collin")) (operating-system-users base-system))) (services (append (list (service cuirass-service-type (cuirass-configuration (host "localhost") (specifications %cuirass-specs) (use-substitutes? #t))) %nginx-cache-activation (service nginx-service-type %nginx-configuration) (service guix-publish-service-type (guix-publish-configuration (port 3000) (cache "/var/cache/guix/publish")))) (modify-services %proxmox-vm-lvm-minimal-services ;; Add and authorize non-guix substitute server (guix-service-type config => (guix-configuration (inherit config) (substitute-urls (append (list "https://substitutes.nonguix.org") (guix-configuration-substitute-urls config))) (authorized-keys (append (list (plain-file "non-guix.pub" "(public-key (ecc (curve Ed25519) (q #C1FD53E5D4CE971933EC50C9F307AE2171A2D3B52C804642A7A35F84F3A4EA98#) ) )")) (guix-configuration-authorized-keys config))))))))))