From: Jakub Czajka Date: Fri, 31 Jul 2026 09:39:21 +0000 (+0000) Subject: [vps] Serve website from nginx via upstream config package X-Git-Url: https://git.ekhem.eu.org/?a=commitdiff_plain;h=01ac334dc9a977045696112d9eb3a7dbcf93bd0f;p=guix.git [vps] Serve website from nginx via upstream config package --- diff --git a/conf/vps/website.scm b/conf/vps/website.scm new file mode 100644 index 0000000..9e507f3 --- /dev/null +++ b/conf/vps/website.scm @@ -0,0 +1,149 @@ +;;; Copyright (c) 2026 Jakub Czajka +;;; License: GPL-3.0 or later. +;;; +;;; website.scm — Static website package served via nginx with SSI. + +(define-module (conf vps website) + #:use-module (gnu packages web) + #:use-module (guix build-system trivial) + #:use-module (ice-9 string-fun) + #:use-module (guix gexp) + #:use-module (guix git-download) + #:use-module (guix packages) + #:use-module ((guix licenses) + #:prefix license:) + #:export (website %public-domain %nginx-site-config)) + +(define %public-domain + "example.org") + +(define website + (package + (name "website") + (version "20240511") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://git.ekhem.eu.org/website.git") + (commit "0a48cd756788223be5a2c1c3865b65fb9a8476c8"))) + (sha256 + (base32 "10038b680vq39ar0r0f2v2br7803r3531zyknycf6zbih6bjyvx5")))) + (build-system trivial-build-system) + (arguments + (list + #:modules '((guix build utils)) + #:builder + #~(begin + (use-modules (guix build utils)) + (let ((out (string-append #$output "/share/website"))) + (mkdir-p out) + (copy-recursively #$source out) + (for-each (lambda (f) + (when (file-exists? (string-append out "/" f)) + (delete-file (string-append out "/" f)))) + '("views.sh" "revision.sh" "create.sql" "drop.sql")))))) + (home-page "https://git.ekhem.eu.org") + (synopsis "Static website files served via nginx with SSI") + (description "HTML and media files for a personal website, +served by nginx with Server-Side Includes.") + (license license:gpl3+))) + +(define %nginx-site-config + (package + (name "nginx-site-config") + (version "0") + (source + #f) + (build-system trivial-build-system) + (inputs (list website nginx)) + (arguments + (list + #:modules '((guix build utils) + (ice-9 rdelim) + (ice-9 string-fun)) + #:builder + #~(begin + (use-modules (guix build utils) + (ice-9 rdelim) + (ice-9 string-fun)) + (let* ((domain #$%public-domain) + (webroot (string-append #$website "/share/website")) + (conf-in (string-append webroot "/website.conf")) + (out-dir (string-append #$output "/share/nginx")) + (out-file (string-append out-dir "/site.conf")) + (mime-types (string-append #$nginx + "/share/nginx/conf/mime.types")) + (skip? #f) + (in-location? #f)) + (mkdir-p out-dir) + (call-with-output-file out-file + (lambda (out) + (format out + "user nginx nginx; +pid /var/run/nginx/pid; +error_log /var/log/nginx/error.log error; +events {} +http { + client_body_temp_path /var/run/nginx/client_body_temp; + proxy_temp_path /var/run/nginx/proxy_temp; + fastcgi_temp_path /var/run/nginx/fastcgi_temp; + uwsgi_temp_path /var/run/nginx/uwsgi_temp; + scgi_temp_path /var/run/nginx/scgi_temp; + access_log /var/log/nginx/access.log combined; + include ~a; + +" + mime-types) + (call-with-input-file conf-in + (lambda (in) + (let lp + ((line (read-line in))) + (unless (eof-object? line) + (set! line + (string-replace-substring line "${dollar}" "$")) + (set! line + (string-replace-substring line + "${public_domain}" + domain)) + (set! line + (string-replace-substring line "${prod_dir}/www" + webroot)) + (set! line + (string-replace-substring line "${prod_dir}" + webroot)) + (set! line + (string-replace-substring line + "${website_log_file}" + "/var/log/nginx/website-access.log")) + (cond + ((or (string-contains line "/views/") + (string-contains line "/revision/")) + (set! in-location? #t)) + ((and in-location? + (string-contains line "}")) + (set! in-location? #f)) + (in-location? #f) + ((string-contains line "return 301 https") + (set! skip? #t)) + ((and skip? + (string-contains line "}")) + (set! skip? #f)) + (skip? #f) + ((or (string-contains line "443") + (string-contains line "ssl_certificate") + (string-contains line "ssl_trusted") + (string-contains line "userid")) + #f) + ((string-contains line "[::]:80") + #f) + ((string-contains line "listen 80") + (display " listen 80;\n" out)) + (else (display line out) + (newline out))) + (lp (read-line in)))))) + (display "}\n" out))))))) + (home-page #f) + (synopsis "Nginx configuration for the website") + (description #f) + (license license:gpl3+))) diff --git a/tests/common.scm b/tests/common.scm index 1b07d61..f24f0ce 100644 --- a/tests/common.scm +++ b/tests/common.scm @@ -5,7 +5,7 @@ (define-module (tests common) #:use-module (guix gexp) - #:export (assert-service-running assert-binary-exists)) + #:export (assert-service-running assert-binary-exists assert-http-200)) (define (assert-service-running label service-name marionette-gexp) "Return a gexp that asserts the Shepherd service SERVICE-NAME is @@ -22,3 +22,26 @@ running." (marionette-eval '(file-exists? (string-append #$pkg "/bin/" #$binary-name)) #$marionette-gexp))) + +(define (assert-http-200 label uri marionette-gexp) + "Return a gexp that asserts an HTTP GET to URI returns 200." + (let ((body `(begin + (use-modules (ice-9 rdelim) + (srfi srfi-13)) + (let* ((req (string-append "GET " + ,uri " HTTP/1.0\r\n\r\n")) + (s (socket PF_INET SOCK_STREAM 0)) + (addr (make-socket-address AF_INET INADDR_LOOPBACK 80))) + (catch 'system-error + (lambda () + (connect s addr) + (display req s) + (force-output s) + (let ((rsp (read-line s))) + (close-port s) + (string-contains rsp "200"))) + (lambda (key . args) + (close-port s) #f)))))) + #~(test-assert #$label + (marionette-eval '#$body + #$marionette-gexp))))