From 355f1bd0fabf2667fa8ce05b083af67b491f5176 Mon Sep 17 00:00:00 2001 From: Azalea Redmyer Date: Thu, 5 Feb 2026 20:33:37 -0800 Subject: Add 'chinstrap' server configuration & supporting files --- bluechateau/systems/chinstrap.scm | 501 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 501 insertions(+) create mode 100644 bluechateau/systems/chinstrap.scm (limited to 'bluechateau/systems') diff --git a/bluechateau/systems/chinstrap.scm b/bluechateau/systems/chinstrap.scm new file mode 100644 index 0000000..bc6ba82 --- /dev/null +++ b/bluechateau/systems/chinstrap.scm @@ -0,0 +1,501 @@ +;; ======================================================================= +;; Guix System configuration for my local server-in-a-closet, `chinstrap`. +;; ======================================================================= +;; +;; TODO: I'd like to split this into separate files. I would also like to +;; rewrite this as a 'literate' configuration at some point in the future. + +(define-module (bluechateau systems chinstrap) + #:use-module (gnu) + #:use-module (gnu packages databases) + #:use-module (gnu packages emacs) + #:use-module (gnu packages guile-xyz) + #:use-module (gnu packages ssh) + #:use-module (gnu packages version-control) + #:use-module (gnu packages web) + #:use-module (gnu services admin) + #:use-module (gnu services certbot) + #:use-module (gnu services cgit) + #:use-module (gnu services containers) + #:use-module (gnu services dbus) + #:use-module (gnu services databases) + #:use-module (gnu services desktop) + #:use-module (gnu services docker) + #:use-module (gnu services networking) + #:use-module (gnu services ssh) + ;;#:use-module (gnu services version-control) + #:use-module (gnu services virtualization) + #:use-module (gnu services web) + #:use-module (gnu system) + #:use-module (guix gexp) + #:use-module (nongnu packages linux) + #:use-module (nongnu system linux-initrd) + #:use-module (bluechateau services version-control)) + +(define ssl-domains '("bluechateau.org" + "www.bluechateau.org" + "git.bluechateau.org" + "search.bluechateau.org" + "fwiki.bluechateau.org" + "vtt.bluechateau.org" + "docs.bluechateau.org" + "sbdocs.bluechateau.org")) + +(define nginx-accounts + (list (user-group (name "nginx") (system? #t)) + (user-account + (name "nginx") + (group "nginx") + (supplementary-groups '("git")) + (system? #t) + (comment "nginx server user") + (home-directory "/var/empty") + (shell (file-append (specification->package "shadow") + "/sbin/nologin"))))) + +;; Override the default nginx service account configuration so +;; the nginx user is a member of the 'git' group. (required for +;; cgit) +(define nginx-service-type* + (service-type + (inherit nginx-service-type) + (extensions + (map (lambda (extension) + (if (eq? (service-extension-target extension) + account-service-type) + (service-extension account-service-type + (const nginx-accounts)) + extension)) + (service-type-extensions nginx-service-type))))) + +(define blog-nginx-server-configuration + (nginx-server-configuration + (listen '("443 ssl")) + (server-name '("bluechateau.org")) + (root "/srv/blog/site/") + (ssl-certificate + "/etc/certs/bluechateau/fullchain.pem") + (ssl-certificate-key + "/etc/certs/bluechateau/privkey.pem"))) + +(define git-fcgiwrap-service + (service fcgiwrap-service-type + (fcgiwrap-configuration + ;; Use 'git' user to read from the Git repositories. + (user "git") + (socket "tcp:127.0.0.1:9000")))) + +;; Gitolite (git repository hosting) +(define gitolite-service + (service gitolite-service-type + (gitolite-configuration + (admin-pubkey (local-file "../../keys/azalea.pub")) + (home-directory "/srv/git") + (rc-file (gitolite-rc-file + ;; Grant read access to 'git' group so + ;; cgit will work. + (umask #o0027) + ;; In order to hide repositories in cgit, + ;; this value must be set. + (git-config-keys ".*") + (extra-content "WRITER_CAN_UPDATE_DESC => 1")))))) + +;; CGit (git repository browser) +(define cgit-service + (let ((cgit (specification->package "cgit"))) + (service (service-type + (inherit cgit-service-type) + (extensions + ;; Replace original nginx-service with + ;; the modified one. + (map (lambda (extension) + (if (eq? (service-extension-target extension) + nginx-service-type) + (service-extension nginx-service-type* + cgit-configuration-nginx-config) + extension)) + (service-type-extensions cgit-service-type)))) + (cgit-configuration + (repository-directory "/srv/git/repositories") + (root-desc "Move slow and build things.") + (enable-git-config? #t) + (enable-http-clone? #f) + (enable-index-links? #t) + (enable-index-owner? #f) + (enable-commit-graph? #t) + (enable-log-filecount? #t) + (enable-log-linecount? #t) + (remove-suffix? #t) + (clone-url '("https://git.bluechateau.org/$CGIT_REPO_URL.git")) + ;; Source code syntax highlighting wrapper script. + (source-filter (program-file + "cgit-syntax-highlight" + #~(apply execl + (string-append #$cgit "/lib/cgit/filters/syntax-highlighting.py") + (command-line)))) + (nginx + (list + (nginx-server-configuration + (listen '("443 ssl")) + (server-name '("git.bluechateau.org")) + (root cgit) + (ssl-certificate + "/etc/certs/bluechateau/fullchain.pem") + (ssl-certificate-key + "/etc/certs/bluechateau/privkey.pem") + (locations + (list + (nginx-location-configuration + (uri "~ (/.*\\.git/.*)") + (body + `("fastcgi_pass 127.0.0.1:9000;" + ("fastcgi_param SCRIPT_FILENAME " + ,git "/libexec/git-core/git-http-backend;") + "fastcgi_param QUERY_STRING $query_string;" + "fastcgi_param REQUEST_METHOD $request_method;" + "fastcgi_param CONTENT_TYPE $content_type;" + "fastcgi_param CONTENT_LENGTH $content_length;" + "fastcgi_param GIT_PROJECT_ROOT /srv/git/repositories;" + "fastcgi_param PATH_INFO $1;"))) + (git-http-nginx-location-configuration + (git-http-configuration + (uri-path "/") + (git-root "/srv/git/repositories") + (export-all? #t))) + (nginx-location-configuration + (uri "~ (/.*)\\.git") + (body + '("return 301 $1;"))) + (nginx-location-configuration + (uri "/") + (body + '("try_files $uri @cgit;"))) + (nginx-location-configuration + (uri "@cgit") + (body '("fastcgi_param SCRIPT_FILENAME $document_root/lib/cgit/cgit.cgi;" + "fastcgi_param PATH_INFO $uri;" + "fastcgi_param QUERY_STRING $args;" + "fastcgi_param HTTP_HOST $server_name;" + "fastcgi_pass 127.0.0.1:9000;")))))))))))) + +(define searxng-oci-container-configuration + (oci-container-configuration + (image "docker.io/searxng/searxng") + (ports + '(("8888" . "8080"))) + (volumes + '("searx-config:/etc/searxng/" + "searx-data:/var/cache/searxng/")))) + +(define searxng-nginx-server-configuration + (nginx-server-configuration + (listen '("443 ssl")) + (server-name '("search.bluechateau.org")) + (ssl-certificate + "/etc/certs/bluechateau/fullchain.pem") + (ssl-certificate-key + "/etc/certs/bluechateau/privkey.pem") + (locations + (list + (nginx-location-configuration + (uri "/") + (body + '("proxy_pass http://localhost:8888;" + "proxy_set_header X-Real-IP $remote_addr;" + "proxy_set_header Host $host;" + "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;"))))))) + +(define cryptpad-config + (plain-file "config.js" + "module.exports = { + httpUnsafeOrigin: 'https://docs.bluechateau.org', + httpSafeOrigin: 'https://sbdocs.bluechateau.org', + httpAddress: '0.0.0.0', + httpPort: 3000, + websocketPort: 3003, + adminKeys: [], + filePath: './datastore/', + archivePath: './data/archive', + pinPath: './data/pins', + taskPath: './data/tasks', + blockPath: './block', + blobPath: './blob', + blobStagingPath: './data/blobstage', + decreePath: './data/decrees', + logPath: './data/logs', + logToStdout: false, + logLevel: 'info', + logFeedback: false, + verbose: false, + installMethod: 'docker', +};")) + +(define cryptpad-oci-container-configuration + (oci-container-configuration + (image "cryptpad/cryptpad") + (ports + '(("3000" . "3000") + ("3003" . "3003"))) + (volumes + `("cryptpad-blob:/cryptpad/blob" + "cryptpad-block:/cryptpad/block" + "cryptpad-customize:/cryptpad/customize" + "cryptpad-data:/cryptpad/data" + "cryptpad-datastore:/cryptpad/datastore" + "cryptpad-onlyoffice-dist:/cryptpad/www/common/onlyoffice/dist" + "cryptpad-onlyoffice-conf:/cryptpad/onlyoffice-conf" + (,cryptpad-config . "/cryptpad/config/config.js"))) + (environment + '("CPAD_MAIN_DOMAIN=https://docs.bluechateau.org" + "CPAD_SANDBOX_DOMAIN=https://sbdocs.bluechateau.org" + "CPAD_CONF=/cryptpad/config/config.js")) + (extra-arguments + '("-h cryptpad")))) + +(define cryptpad-nginx-server-configuration + (nginx-server-configuration + (listen '("443 ssl")) + (server-name '("docs.bluechateau.org" + "sbdocs.bluechateau.org")) + (ssl-certificate + "/etc/certs/bluechateau/fullchain.pem") + (ssl-certificate-key + "/etc/certs/bluechateau/privkey.pem") + (raw-content + '("ssl_dhparam /srv/cryptpad/dhparam.pem;" + "ssl_session_timeout 1d;" + "ssl_session_cache shared:MozSSL:10m;" + "ssl_session_tickets off;" + "ssl_protocols TLSv1.2 TLSv1.3;" + "ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;" + "ssl_prefer_server_ciphers off;" + "add_header Strict-Transport-Security \"max-age=63072000; includeSubDomains\" always;")) + (locations + (list + (nginx-location-configuration + (uri "/") + (body + '("proxy_pass http://localhost:3000;" + "proxy_set_header X-Real-IP $remote_addr;" + "proxy_set_header Host $host;" + "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;" + "client_max_body_size 150m;" + "proxy_http_version 1.1;" + "proxy_set_header Upgrade $http_upgrade;" + "proxy_set_header Connection upgrade;"))) + (nginx-location-configuration + (uri "^~ /cryptpad_websocket") + (body + '("proxy_pass http://localhost:3003;" + "proxy_set_header X-Real-IP $remote_addr;" + "proxy_set_header Host $host;" + "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;" + "proxy_http_version 1.1;" + "proxy_set_header Upgrade $http_upgrade;" + "proxy_set_header Connection upgrade;"))))))) + +(define planarally-config + (plain-file "config.toml" + "[general] +save_file = \"data/planar.sqlite\" +admin_user = \"azalea\" +allow_signups = true +enable_export = true +max_log_size_in_bytes = 200000 +max_log_backups = 5 + +[assets] +max_single_asset_size_in_bytes = 0 +max_total_asset_size_in_bytes = 0 + +[webserver] +max_upload_size_in_bytes = 10485760 + +[webserver.connection] +type = \"hostport\" +host = \"0.0.0.0\" +port = 8000")) + +(define planarally-oci-container-configuration + (oci-container-configuration + (image "kruptein/planarally") + (ports + '(("8000" . "8000"))) + (volumes + `("pa-data:/planarally/data" + "pa-assets:/planarally/static/assets" + "pa-mods:/planarally/static/mods" + (,planarally-config . "/planarally/data/config.toml"))))) + +(define planarally-nginx-server-configuration + (nginx-server-configuration + (listen '("443 ssl")) + (server-name '("vtt.bluechateau.org")) + (ssl-certificate + "/etc/certs/bluechateau/fullchain.pem") + (ssl-certificate-key + "/etc/certs/bluechateau/privkey.pem") + (locations + (list + (nginx-location-configuration + (uri "/") + (body + '("proxy_set_header Host $http_host;" + "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;" + "proxy_redirect off;" + "proxy_buffering off;" + "proxy_set_header X-Real-IP $remote_addr;" + "proxy_pass http://localhost:8000;"))) + (nginx-location-configuration + (uri "/socket.io/") + (body + '("proxy_http_version 1.1;" + "proxy_set_header Upgrade $http_upgrade;" + "proxy_set_header Connection \"Upgrade\";" + "proxy_set_header Host $host;" + "proxy_pass http://localhost:8000/socket.io/;"))))))) + +(define funhole-nginx-server-configuration + (nginx-server-configuration + (listen '("443 ssl")) + (server-name '("fwiki.bluechateau.org")) + (root "/srv/fwiki/") + (ssl-certificate + "/etc/certs/bluechateau/fullchain.pem") + (ssl-certificate-key + "/etc/certs/bluechateau/privkey.pem") + (locations + (list + (nginx-location-configuration + (uri "/") + (body + `(("default_type text/html;") + "try_files $uri $uri/ =404;"))))))) + +(define chinstrap + (operating-system + (kernel linux) + (firmware (list linux-firmware)) + (initrd microcode-initrd) + (locale "en_US.utf8") + (timezone "America/Los_Angeles") + (keyboard-layout (keyboard-layout "us")) + (host-name "chinstrap") + + (users (cons* (user-account + (name "moshimoshi") + (comment "Captain 'Moshi-Moshi' Momo") + (group "users") + (home-directory "/home/moshimoshi") + (supplementary-groups + '("docker" "git" "netdev" "wheel"))) + %base-user-accounts)) + + (bootloader (bootloader-configuration + (bootloader grub-efi-bootloader) + (targets (list "/boot/efi")) + (keyboard-layout keyboard-layout))) + + (file-systems (cons* (file-system + (mount-point "/boot/efi") + (device (uuid "BBEC-EE14" + 'fat32)) + (type "vfat")) + (file-system + (mount-point "/") + (device (uuid + "74a221a4-2d9d-4250-b0de-cb5a6a5962ae" + 'ext4)) + (type "ext4")) %base-file-systems)) + + (swap-devices (list (swap-space + (target (uuid + "a46ba488-1ad1-4c5e-a4f6-e177d4c498aa"))))) + + (packages + (append + (map specification->package + '("emacs" "git")) + %base-packages)) + + (services + (append + (list + ;; Basic system services + (service dhcpcd-service-type) + (service dbus-root-service-type) + (service elogind-service-type) + + ;; OpenSSH + (service openssh-service-type + (openssh-configuration + (openssh openssh-sans-x) + (port-number 22))) + + ;; Docker containers & virtual machines + (service containerd-service-type) + (service docker-service-type) + (service libvirt-service-type + (libvirt-configuration + (unix-sock-group "libvirt") + (tls-port "16555"))) + (simple-service 'oci-service + oci-service-type + (oci-extension + (containers + (list + ;; SearXNG + searxng-oci-container-configuration + ;; CryptPad + cryptpad-oci-container-configuration + ;; PlanarAlly + planarally-oci-container-configuration)))) + + ;; Certbot (TLS certificates) + ;; Certbot extends nginx with configuration to + ;; redirect all HTTP requests to HTTPS. + (service (service-type + (inherit certbot-service-type) + (extensions + ;; Replace original nginx-service with + ;; the modified one. + (map (lambda (extension) + (if (eq? (service-extension-target extension) + nginx-service-type) + (service-extension nginx-service-type* + (@@ (gnu services certbot) + certbot-nginx-server-configurations)) + extension)) + (service-type-extensions certbot-service-type)))) + (certbot-configuration + (email "mononoke@anche.no") + (certificates + (list + (certificate-configuration + (name "bluechateau") + (domains ssl-domains)))))) + + ;; NGINX (web hosting) + ;; Be sure to use the custom service defined at the + ;; top of this file! + (service nginx-service-type* + (nginx-configuration + (server-blocks + (list + ;; Static content + blog-nginx-server-configuration + ;; SearXNG + searxng-nginx-server-configuration + ;; Funhole wiki mirror + funhole-nginx-server-configuration + ;; CryptPad + cryptpad-nginx-server-configuration + ;; PlanarAlly VTT + planarally-nginx-server-configuration)))) + + git-fcgiwrap-service + gitolite-service + cgit-service) + %base-services)))) + +chinstrap -- cgit v1.2.3