From: Jakub Czajka Date: Mon, 20 Jul 2026 22:14:56 +0000 (+0000) Subject: [vps] Add nginx web server on port 80. X-Git-Url: https://git.ekhem.eu.org/?a=commitdiff_plain;h=5a8bd55265a3dd7054093b877904a0fbd58ec8a4;p=guix.git [vps] Add nginx web server on port 80. Co-Authored-By: Claude --- diff --git a/conf/vps/nginx.conf b/conf/vps/nginx.conf new file mode 100644 index 0000000..63255e7 --- /dev/null +++ b/conf/vps/nginx.conf @@ -0,0 +1,35 @@ +user nginx nginx; +pid /var/run/nginx/pid; +error_log /var/log/nginx/error.log error; + +events { + worker_connections 1024; +} + +http { + include @MIME_TYPES@; + default_type application/octet-stream; + + sendfile on; + tcp_nopush on; + keepalive_timeout 65; + server_tokens off; + + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_types text/plain text/css text/xml + application/json application/javascript + application/xml+rss image/svg+xml; + + 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 @SITES_DIR@/*.conf; +} diff --git a/conf/vps/nginx.scm b/conf/vps/nginx.scm new file mode 100644 index 0000000..eeb8211 --- /dev/null +++ b/conf/vps/nginx.scm @@ -0,0 +1,117 @@ +;;; Copyright (c) 2026 Jakub Czajka +;;; License: GPL-3.0 or later. +;;; +;;; nginx.scm — Nginx server configuration, with site configs +;;; collected from all site package inputs under +;;; etc/nginx/sites-available/. + +(define-module (conf vps nginx) + #:use-module (conf vps website) + #:use-module (gnu packages tls) + #:use-module (gnu packages web) + #:use-module (gnu services) + #:use-module (gnu services web) + #:use-module (guix packages) + #:use-module (guix build-system trivial) + #:use-module (guix gexp) + #:use-module ((guix licenses) + #:prefix license:) + #:use-module (ice-9 ftw) + #:use-module (srfi srfi-1) + #:export (nginx-config %nginx-service)) + +(define nginx-config-file + (local-file (canonicalize-path (string-append (getenv "GUIX_PACKAGE_PATH") + "/conf/vps/nginx.conf")) + "nginx.conf")) + +(define nginx-config + (package + (name "nginx-config") + (version "20260725") + (source + nginx-config-file) + (build-system trivial-build-system) + (arguments + (list + #:modules '((guix build utils) + (ice-9 ftw) + (srfi srfi-1)) + #:builder + #~(begin + (use-modules (guix build utils) + (ice-9 ftw) + (srfi srfi-1)) + (let* ((out #$output) + (etc (string-append out "/etc/nginx")) + (sites (string-append etc "/sites-available"))) + (mkdir-p sites) + ;; 1. Copy and patch the main nginx.conf. + (copy-file #$source + (string-append etc "/nginx.conf")) + (substitute* (string-append etc "/nginx.conf") + (("@MIME_TYPES@") + #$(file-append nginx "/share/nginx/conf/mime.types")) + (("@SITES_DIR@") + sites)) + ;; 1.5. Generate a self-signed certificate so that + ;; nginx -t passes even without real SSL certs. + (let* ((openssl-bin #$(file-append openssl "/bin/openssl")) + (certs (string-append out "/etc/nginx/certs"))) + (mkdir-p certs) + (invoke openssl-bin + "req" + "-x509" + "-newkey" + "rsa:2048" + "-keyout" + (string-append certs "/privkey.pem") + "-out" + (string-append certs "/fullchain.pem") + "-days" + "365" + "-nodes" + "-subj" + "/CN=example.org")) + ;; 2. Symlink site configs from all inputs. + (define (site-configs dir) + "Return the list of .conf files in DIR." + (filter (lambda (f) + (string-suffix? ".conf" f)) + (or (scandir dir) + '()))) + (define (collect input) + "Symlink site configs from INPUT into sites/." + (let ((dir (string-append (cdr input) + "/etc/nginx/sites-available"))) + (when (directory-exists? dir) + (unless (member (car input) + '("source" "nginx")) + (for-each (lambda (f) + (symlink (string-append dir "/" f) + (string-append sites "/" f))) + (site-configs dir)))))) + (for-each collect %build-inputs) + ;; 3. Substitute the SSL cert directory in + ;; site configs so nginx -t passes. + (let ((certs (string-append out "/etc/nginx/certs"))) + (for-each (lambda (f) + (substitute* (string-append sites "/" f) + (("\\$\\{public_ssl_cert_dir\\}") + certs))) + (site-configs sites))))))) + (inputs (list nginx openssl website)) + (home-page "https://git.ekhem.eu.org") + (synopsis "Nginx configuration for the personal VPS") + (description "Nginx configuration bundling @file{nginx.conf} and +site-specific configurations auto-collected from all +site package inputs under +@file{etc/nginx/sites-available/}.") + (license license:gpl3+))) + +(define %nginx-config + (let ((conf (file-append nginx-config "/etc/nginx/nginx.conf"))) + (nginx-configuration (file conf)))) + +(define %nginx-service + (service nginx-service-type %nginx-config)) diff --git a/tests/nginx.scm b/tests/nginx.scm new file mode 100644 index 0000000..c7ea83f --- /dev/null +++ b/tests/nginx.scm @@ -0,0 +1,32 @@ +;;; Copyright (c) 2026 Jakub Czajka +;;; License: GPL-3.0 or later. +;;; +;;; nginx test cases. + +(define-module (tests nginx) + #:use-module (conf vps website) + #:use-module (gnu packages web) + #:use-module (guix gexp) + #:export (nginx-test-cases)) + +(define %nginx-binary + (file-append nginx "/sbin/nginx")) + +(define (nginx-test-cases marionette) + "Return a gexp with nginx test assertions." + #~(begin + (test-assert "nginx: service running" + (marionette-eval + '(begin (use-modules (gnu services herd)) + (start-service 'nginx)) + #$marionette)) + + (test-assert "nginx: port 80 TCP" + (wait-for-tcp-port 80 #$marionette)) + + (test-assert "nginx: config syntax is valid" + (marionette-eval + '(zero? (system* #$%nginx-binary + "-c" "/etc/nginx/nginx.conf" + "-t")) + #$marionette)))) diff --git a/vps-system.scm b/vps-system.scm index 2258573..30d69dd 100644 --- a/vps-system.scm +++ b/vps-system.scm @@ -13,6 +13,7 @@ #:use-module (nongnu packages linux) #:use-module (conf vps sshd) #:use-module (conf vps dnscrypt) + #:use-module (conf vps nginx) #:export (vps-operating-system)) (use-service-modules networking shepherd) @@ -81,6 +82,8 @@ ;; etc-service-type rather than being one. (service resolv-conf-service-type) + %nginx-service + ;; TODO: nginx stream for DNS-over-TLS on port 853. ;; See server.git dnscrypt-proxy/dnscrypt-proxy.conf ;; and the metadata.git Ansible playbook for the