aboutsummaryrefslogtreecommitdiff
path: root/salamina.scm
diff options
context:
space:
mode:
Diffstat (limited to 'salamina.scm')
-rw-r--r--salamina.scm805
1 files changed, 805 insertions, 0 deletions
diff --git a/salamina.scm b/salamina.scm
new file mode 100644
index 0000000..dd5618d
--- /dev/null
+++ b/salamina.scm
@@ -0,0 +1,805 @@
+;; SPDX-License-Identifier: CC0-1.0
+
+;; Copyright (C) 2022-2024 W. Kosior <koszko@koszko.org>
+;;
+;; Available under the terms of Creative Commons Zero v1.0 Universal.
+
+(use-modules ((srfi srfi-1) #:select (append-map))
+ ((srfi srfi-26) #:select (cut))
+
+ ((ice-9 format) #:select (format))
+ ((ice-9 match) #:select (match-lambda))
+
+ ((gnu bootloader) #:select (bootloader-configuration))
+ ((gnu bootloader grub) #:select (grub-bootloader))
+
+ ((gnu packages) #:select (specifications->packages))
+ ((gnu packages admin) #:select (shadow))
+ ((gnu packages koszko-services) #:prefix ks:)
+ ((gnu packages python) #:select (guix-pythonpath-search-path))
+ ((gnu packages web) #:select (httpd mod-wsgi))
+ ((gnu packages version-control) #:select (git cgit))
+
+ ((gnu services) #:select
+ (activation-service-type service simple-service))
+ ((gnu services base) #:select
+ (guix-service-type guix-extension %base-services))
+ ((gnu services ssh) #:select
+ (openssh-service-type openssh-configuration))
+ ((gnu services networking) #:select (dhcp-client-service-type))
+ ((gnu services overlayfs) #:select
+ (overlayfs-service-type overlayfs-mount-configuration))
+ ((gnu services web) #:prefix web:)
+ ((gnu services cgit) #:select
+ (cgit-configuration serialize-cgit-configuration))
+ ((gnu services certbot) #:prefix cb:)
+ ((gnu services dns) #:prefix dns:)
+ ((gnu services mail) #:prefix mail:)
+ ((gnu services version-control) #:prefix vc:)
+ ((gnu services databases) #:select
+ (postgresql-service-type postgresql-configuration))
+
+ ((gnu system) #:select (%base-packages operating-system))
+ ((gnu system file-systems) #:prefix fs:)
+ ((gnu system keyboard) #:select (keyboard-layout))
+ ((gnu system shadow) #:prefix gss:)
+
+ ((guix build-system python) #:select (default-python))
+ ((guix gexp) #:select
+ (gexp local-file file-append plain-file program-file
+ mixed-text-file with-imported-modules))
+ ((guix modules) #:select (source-module-closure))
+ ((guix packages) #:select
+ (package-transitive-target-inputs package-version))
+ ((guix search-paths) #:select (search-path-specification->sexp)))
+
+(define %services
+ %base-services)
+
+(define-syntax-rule (prepend list item)
+ (define list
+ (cons item list)))
+
+(prepend %services
+ (service dhcp-client-service-type))
+
+(prepend %services
+ (simple-service 'always-forbid-root-login activation-service-type
+ #~(system "/run/setuid-programs/passwd -l root > /dev/null")))
+
+(prepend %services
+ (simple-service 'guix-authorize-key guix-service-type
+ (guix-extension
+ (authorized-keys (list (local-file "guix-signing-key.pub"))))))
+
+(prepend %services
+ (service web:httpd-service-type
+ (web:httpd-configuration
+ (config
+ (web:httpd-config-file
+ (server-name "koszko.org")
+ (listen '("80" "443"))
+ (error-log "/var/log/httpd/error.log")
+ (modules (append
+ (map (lambda (name)
+ (let ((filename (format #f "/modules/mod_~a.so" name)))
+ (web:httpd-module
+ (name (string-append name "_module"))
+ (file (file-append httpd filename)))))
+ (list "cgid"
+ "logio"
+ "rewrite"
+ "ssl"
+ "proxy"
+ "proxy_http"
+ "headers"))
+ (list (web:httpd-module
+ (name "wsgi_module")
+ (file (file-append mod-wsgi "/modules/mod_wsgi.so"))))
+ web:%default-httpd-modules))
+ (extra-config
+ (list "\
+ LogFormat \"%>s %u %t \\\"%r\\\" %I in %O out \
+\\\"%{Referer}i\\\" \\\"%{User-Agent}i\\\"\" combined
+ CustomLog /var/log/httpd/access.log combined
+ ScriptSock /var/run/cgid.sock
+ ")))))))
+
+(prepend %services
+ (simple-service 'acme-challenge-http-virtualhost web:httpd-service-type
+ (map (match-lambda
+ ((main-domain . other-domains)
+ (web:httpd-virtualhost
+ "*:80"
+ `("\
+ ServerName " ,main-domain "
+ " ,(format #f "~{ServerAlias ~a~^~%~}" other-domains) "
+ ServerAdmin webmaster@koszko.org
+ <If \"%{HTTP_HOST} != '" ,main-domain "'\">
+ Redirect permanent / http://" ,main-domain "/
+ </If>
+ #<ElseIf \"true && (%{REQUEST_URI} !~ \
+ # m#^/[.]well-known/acme-challenge/.*#)\">
+ # Redirect permanent / https://" ,main-domain "/
+ #</ElseIf>
+ DocumentRoot /var/empty
+ Alias /.well-known/acme-challenge \
+ /var/certbot-validation/.well-known/acme-challenge
+ "))))
+ '(("koszko.org" "www.koszko.org"
+ "koszkonutek-tmp.pl.eu.org" "www.koszkonutek-tmp.pl.eu.org")
+ ("git.koszko.org" "www.git.koszko.org"
+ "git.koszkonutek-tmp.pl.eu.org" "www.git.koszkonutek-tmp.pl.eu.org"
+ "git.happyhacking.pl" "www.git.happyhacking.pl")
+ ("haketilo.koszko.org" "www.haketilo.koszko.org")
+ ("hydrilla.koszko.org")
+ ("hydrillabugs.koszko.org" "www.hydrillabugs.koszko.org"
+ "hachettebugs.koszko.org" "www.hachettebugs.koszko.org")
+ ("imap.koszko.org")
+ ("pray.koszko.org" "www.pray.koszko.org")
+ ("sheets.koszko.org" "www.sheets.koszko.org")
+ ("smtp.koszko.org")))))
+
+(define %cgitrc
+ (serialize-cgit-configuration
+ (cgit-configuration
+ (about-filter (file-append cgit "/lib/cgit/filters/about-formatting.sh"))
+ (cache-root "/var/cache/cgit")
+ (cache-size 1000)
+ ;; Snapshots are likely to get pretty big and there seems to be no simple
+ ;; way to limit cache size by bytes rather than a number of entries. Let's
+ ;; disable snapshot cache entirely to avoid running out of disk space.
+ (cache-snapshot-ttl 0)
+ (css "/cgit-static/cgit.css")
+ (enable-index-links? #t)
+ (enable-index-owner? #f)
+ (favicon "/cgit-static/favicon.ico")
+ (footer (plain-file "cgit-footer"
+ "\
+ <div class=footer>generated by
+ <a href=\"https://git.zx2c4.com/cgit/about/\">
+ cgit
+ </a>
+ </div>
+ "))
+ (logo "https://git.koszko.org/cgit-static/cgit.png")
+ (max-blob-size 100)
+ ;; Owners are not used in this setup but cgit nevertheless tries to deduce
+ ;; them from the filesystem&passwd and presents "Gitolite user" as the owner
+ ;; in the UI. This hack hides that string from visitors.
+ (owner-filter (program-file "dummy-format-owner" #~(noop)))
+ (project-list "/var/lib/gitolite/projects.list")
+ (remove-suffix? #t)
+ (repository-directory "/var/lib/gitolite/repositories")
+ (root-desc "Repositories of Wojtek")
+ (snapshots '("tar.gz" "zip"))
+ (extra-options (append
+ ;; Setting `js` option to an empty list removes JS from the
+ ;; UI.
+ '("js=")
+ ;; TODO: improve Guix' cgit-configuration to allow passing
+ ;; multiple CSS files.
+ '("css=/cgit-static/better-cgit-markdown-heading-color.css")
+ (append-map
+ (lambda (file-name)
+ (map (cut string-append "readme=:" file-name <>)
+ '(".md" ".mkd" ".rst" ".html" ".htm" ".txt" "")))
+ '("readme" "README" "install" "INSTALL")))))))
+
+(define %better-cgit-markdown-heading-color.css
+ (mixed-text-file "better-cgit-markdown-heading-color.css"
+ (format #f "~{.markdown-body h~a a~^,~%~} " (iota 6 1))
+ "{ color: #555 !important; }"))
+
+(prepend %services
+ (simple-service 'cgit-http-virtualhost web:httpd-service-type
+ (list (web:httpd-virtualhost
+ "*:443"
+ `("\
+ ServerName git.koszko.org
+ ServerAlias www.git.koszko.org
+ ServerAlias git.koszkonutek-tmp.pl.eu.org
+ ServerAlias www.git.koszkonutek-tmp.pl.eu.org
+ ServerAlias git.happyhacking.pl
+ ServerAlias www.git.happyhacking.pl
+ ServerAdmin webmaster@koszko.org
+
+ <If \"%{HTTP_HOST} != 'git.koszko.org'\">
+ Redirect permanent / https://git.koszko.org/
+ </If>
+
+ <Directory " ,(file-append git "/libexec/git-core") ">
+ Require all granted
+ SetEnv GIT_PROJECT_ROOT /var/lib/gitolite/repositories
+ </Directory>
+ ScriptAliasMatch \
+ ^/(.*/(HEAD|info/refs|objects/info/[^/]+|git-upload-pack))$ \
+ " ,(file-append git "/libexec/git-core/git-http-backend/$1") "
+
+ Alias /cgit-static/better-cgit-markdown-heading-color.css \
+ " ,%better-cgit-markdown-heading-color.css "
+ Alias /cgit-static " ,(file-append cgit "/share/cgit") "
+
+ SetEnv CGIT_CONFIG " ,(mixed-text-file "cgitrc" %cgitrc) "
+ ScriptAlias / " ,(file-append cgit "/lib/cgit/cgit.cgi/") "
+ <Directory " ,(file-append cgit "/lib/cgit/") ">
+ Options +ExecCGI
+ </Directory>
+
+ SSLEngine on
+ SSLCertificateFile /etc/certs/git.koszko.org/fullchain.pem
+ SSLCertificateKeyFile /etc/certs/git.koszko.org/privkey.pem
+ ")))))
+
+(prepend %services
+ (simple-service 'prepare-cgit-cache-dir activation-service-type
+ #~(begin
+ (mkdir-p "/var/cache/cgit")
+ (chown "/var/cache/cgit" -1 (group:gid (getgr "httpd")))
+ (chmod "/var/cache/cgit" #o770))))
+
+(prepend %services
+ (simple-service 'demo-01-http-virtualhost web:httpd-service-type
+ (list (web:httpd-virtualhost
+ "*:443"
+ `("\
+ ServerName demo-01.happyhacking.pl
+ ServerAlias www.demo-01.happyhacking.pl
+ ServerAdmin webmaster@happyhacking.pl
+
+ <If \"%{HTTP_HOST} != 'demo-01.happyhacking.pl'\">
+ Redirect permanent / https://demo-01.happyhacking.pl/
+ </If>
+
+ ProxyPass / http://127.0.0.1:5050/
+ ProxyPassReverse / http://127.0.0.1:5050/
+
+ Header add Content-Security-Policy \"img-src 'self' data:; connect-src 'self'; default-src ws: 'self' data: blob: 'unsafe-inline' 'unsafe-eval';\"
+
+ SSLEngine on
+ SSLCertificateFile \
+ /etc/certs/demo-01.happyhacking.pl/fullchain.pem
+ SSLCertificateKeyFile \
+ /etc/certs/demo-01.happyhacking.pl/privkey.pem
+ ")))))
+
+(prepend %services
+ (simple-service 'httpd-virtualhost-koszko web:httpd-service-type
+ (list (let ((wsgi (file-append ks:koszko-org-website
+ "/share/koszko-org-website/wsgi.py")))
+ (web:httpd-virtualhost
+ "*:443"
+ `("\
+ ServerName koszko.org
+ ServerAlias www.koszko.org
+ ServerAlias koszkonutek-tmp.pl.eu.org
+ ServerAlias www.koszkonutek-tmp.pl.eu.org
+ ServerAdmin koszko@koszko.org
+
+ <If \"%{HTTP_HOST} != 'koszko.org'\">
+ Redirect permanent / https://koszko.org/
+ </If>
+
+ DocumentRoot /srv/http/koszko.org
+ Alias /sideload /srv/http/koszko.org
+ <Files " ,wsgi ">
+ Require all granted
+ </Files>
+ WSGIScriptAlias / " ,wsgi "
+
+ SSLEngine on
+ SSLCertificateFile /etc/certs/koszko.org/fullchain.pem
+ SSLCertificateKeyFile /etc/certs/koszko.org/privkey.pem
+ "))))))
+
+(prepend %services
+ (simple-service 'httpd-virtualhost-haketilo web:httpd-service-type
+ (list (let ((wsgi (file-append ks:hydrilla-website
+ "/share/hydrilla-website/wsgi.py")))
+ (web:httpd-virtualhost
+ "*:443"
+ `("\
+ ServerName haketilo.koszko.org
+ ServerAlias www.haketilo.koszko.org
+ ServerAdmin koszko@koszko.org
+
+ <If \"%{HTTP_HOST} != 'haketilo.koszko.org'\">
+ Redirect permanent / https://haketilo.koszko.org/
+ </If>
+
+ <Files " ,wsgi ">
+ Require all granted
+ </Files>
+ WSGIScriptAlias / " ,wsgi "
+
+ SSLEngine on
+ SSLCertificateFile /etc/certs/haketilo.koszko.org/fullchain.pem
+ SSLCertificateKeyFile /etc/certs/haketilo.koszko.org/privkey.pem
+ "))))))
+
+(define %python-path-spec-sexp
+ (search-path-specification->sexp
+ (guix-pythonpath-search-path (package-version (default-python)))))
+
+(define %hydrilla-pythonpath-inputs
+ (cons ks:hydrilla-without-haketilo
+ (map cadr (package-transitive-target-inputs
+ ks:hydrilla-without-haketilo))))
+
+(define %hydrilla-pythonpath-gexp
+ (with-imported-modules (source-module-closure '((guix search-paths)))
+ #~(begin
+ (use-modules ((guix search-paths) #:prefix sp:))
+
+ (let ((evaluated-list (sp:evaluate-search-paths
+ (list (sp:sexp->search-path-specification
+ '#$%python-path-spec-sexp))
+ '#$%hydrilla-pythonpath-inputs)))
+ (cdar evaluated-list)))))
+
+(prepend %services
+ (simple-service 'httpd-virtualhost-hydrilla web:httpd-service-type
+ (list (web:httpd-virtualhost
+ "*:443"
+ `("\
+ ServerName hydrilla.koszko.org
+ ServerAdmin webmaster@koszko.org
+
+ <If \"%{HTTP_HOST} != 'hydrilla.koszko.org'\">
+ Redirect permanent / https://hydrilla.koszko.org/
+ </If>
+
+ Alias /downloads /srv/http/hydrilla.koszko.org/downloads
+
+ Alias /schemas \
+ " ,(file-append ks:hydrilla-json-schemas-all
+ "/share/hydrilla-json-schemas") "
+
+ DocumentRoot /var/lib/hydrilla/malcontent_dirs
+
+ <Location ~ ^/api_v[^/]+/(resource|mapping)/>
+ ForceType application/json
+ </Location>
+
+ SetEnvIf Request_URI ^/(api_v[0-9]+)/ \
+ MALCONENT_DIR=/var/lib/hydrilla/malcontent_dirs/$1
+
+ SetEnvIf Request_URI ^/api_v[0-9]+/ \
+ HYDRILLA_GUIX_PYTHONPATH=" ,%hydrilla-pythonpath-gexp "
+
+ WSGIScriptAliasMatch \
+ ^/api_v[^/]+/((resource|mapping)/[^/]+[.]json|query|list_all)$ \
+ " ,(local-file "hydrilla-wsgi.py") "/$1
+
+ SSLEngine on
+ SSLCertificateFile \
+ /etc/certs/hydrilla.koszko.org/fullchain.pem
+ SSLCertificateKeyFile \
+ /etc/certs/hydrilla.koszko.org/privkey.pem
+ ")))))
+
+(prepend %services
+ (simple-service 'httpd-virtualhost-hydrillabugs web:httpd-service-type
+ (list (web:httpd-virtualhost
+ "*:443"
+ `("\
+ ServerName hydrillabugs.koszko.org
+ ServerAlias www.hydrillabugs.koszko.org
+ ServerAlias hachettebugs.koszko.org
+ ServerAlias www.hachettebugs.koszko.org
+ ServerAdmin webmaster@koszko.org
+
+ <If \"%{HTTP_HOST} != 'hydrillabugs.koszko.org'\">
+ Redirect permanent / https://hydrillabugs.koszko.org/
+ </If>
+
+ DocumentRoot /srv/http/hydrillabugs.koszko.org
+
+ RewriteEngine On
+
+ RewriteCond %{REQUEST_METHOD} !GET
+ RewriteRule ^(.*)$ /hydrillabugs-archived.html [L,R=301,QSD]
+
+ Alias /hydrillabugs-archived.html \
+ " ,(local-file "hydrillabugs-archived.html") "
+
+ RewriteRule /uri-map.txt /dummy [L,F]
+
+ # Serve wget-archived website.
+ RewriteMap add-ext \
+ txt:/srv/http/hydrillabugs.koszko.org/uri-map.txt
+
+ <Location /javascripts>
+ ForceType application/javascript
+ </Location>
+
+ # Make `hachette' project display under the name `haketilo'.
+ RewriteRule ^/projects/haketilo(.*)$ /projects/hachette$1
+
+ RewriteCond %{QUERY_STRING} !^$
+ RewriteCond ${add-ext:$1?%{QUERY_STRING}|NONE} !NONE
+ RewriteRule ^(.*)$ ${add-ext:$1?%{QUERY_STRING}} [L,R=301]
+ RewriteCond %{QUERY_STRING} !^$
+ RewriteRule ^(.*)$ $1?%{QUERY_STRING}? [L,QSL]
+ RewriteCond %{QUERY_STRING} ^$
+ RewriteCond ${add-ext:$1|NONE} !NONE
+ RewriteRule ^(.*)$ ${add-ext:$1} [L,R=301]
+
+ SSLEngine on
+ SSLCertificateFile \
+ /etc/certs/hydrillabugs.koszko.org/fullchain.pem
+ SSLCertificateKeyFile \
+ /etc/certs/hydrillabugs.koszko.org/privkey.pem
+ ")))))
+
+(prepend %services
+ (simple-service 'httpd-virtualhost-sheets web:httpd-service-type
+ (map (lambda (what)
+ (define website-files
+ (file-append ks:sheets-websites
+ (format #f "/share/~a-website" what)))
+
+ (web:httpd-virtualhost
+ "*:443"
+ `("\
+ ServerName " ,what ".koszko.org
+ ServerAlias www." ,what ".koszko.org
+ ServerAdmin koszko@koszko.org
+
+ <If \"%{HTTP_HOST} != '" ,what ".koszko.org'\">
+ Redirect permanent / https://" ,what ".koszko.org/
+ </If>
+
+ DocumentRoot " ,website-files "
+
+ SSLEngine on
+ SSLCertificateFile /etc/certs/" ,what ".koszko.org/fullchain.pem
+ SSLCertificateKeyFile /etc/certs/" ,what ".koszko.org/privkey.pem
+ ")))
+ '("pray" "sheets"))))
+
+(define %certbot-deploy-hook
+ (program-file "httpd-deploy-hook"
+ #~(for-each (lambda (pidfile)
+ (false-if-exception
+ (kill (call-with-input-file pidfile read) SIGHUP)))
+ '("/var/run/httpd"
+ "/var/spool/exim/exim-daemon.pid"
+ "/var/run/dovecot/master.pid"))))
+
+(prepend %services
+ (service cb:certbot-sans-nginx-service-type
+ (cb:certbot-configuration
+ (webroot "/var/certbot-validation")
+ (certificates
+ (map (match-lambda
+ ((domains . key-read-group)
+ (cb:certificate-configuration
+ (name (car domains))
+ (domains domains)
+ (deploy-hook %certbot-deploy-hook)
+ (key-read-group key-read-group))))
+ '((("koszko.org" "www.koszko.org"
+ "koszkonutek-tmp.pl.eu.org" "www.koszkonutek-tmp.pl.eu.org")
+ . #f)
+ (("git.koszko.org" "www.git.koszko.org"
+ "git.koszkonutek-tmp.pl.eu.org"
+ "www.git.koszkonutek-tmp.pl.eu.org"
+ "git.happyhacking.pl" "www.git.happyhacking.pl") . #f)
+ (("haketilo.koszko.org" "www.haketilo.koszko.org") . #f)
+ (("hydrilla.koszko.org") . #f)
+ (("hydrillabugs.koszko.org" "www.hydrillabugs.koszko.org"
+ "hachettebugs.koszko.org" "www.hachettebugs.koszko.org") . #f)
+ (("imap.koszko.org") . #f)
+ (("pray.koszko.org" "www.pray.koszko.org") . #f)
+ (("sheets.koszko.org" "www.sheets.koszko.org") . #f)
+ (("smtp.koszko.org") . "smtp-certificates"))))
+ (email "koszko@koszko.org")
+ (rsa-key-size 4096)
+ (service-reload '())
+ (service-requirement '(httpd)))))
+
+(prepend %services
+ (simple-service 'prepare-certbot-tokens-dir activation-service-type
+ #~(mkdir-p "/var/certbot-validation")))
+
+(define (make-koszko-zone-entries domain)
+ (dns:define-zone-entries entries
+ ;; nameservers
+ ("@" "" "IN" "NS" (format #f "ns2.~a." domain))
+ ("@" "" "IN" "NS" "ns0.1984.is.")
+ ("@" "" "IN" "NS" "ns1.1984.is.")
+ ("@" "" "IN" "NS" "ns2.1984.is.")
+ ("@" "" "IN" "NS" "ns1.1984hosting.com.")
+ ("@" "" "IN" "NS" "ns2.1984hosting.com.")
+
+ ;; domain->IP assignments
+ ("@" "" "IN" "A" "188.68.237.248")
+
+ ("antioch" "" "IN" "A" "188.68.236.76")
+ ("*.antioch" "" "IN" "CNAME" "antioch")
+ ("salamina" "" "IN" "A" "188.68.237.248")
+ ("*.salamina" "" "IN" "CNAME" "salamina")
+
+ ("ctftilde" "" "IN" "A" "127.0.0.1")
+ ("ctftilde" "" "IN" "AAAA" "::1")
+ ("*.ctftilde" "" "IN" "CNAME" "ctftilde")
+
+ ("git" "" "IN" "CNAME" "salamina")
+ ("www.git" "" "IN" "CNAME" "git")
+ ("hachettebugs" "" "IN" "CNAME" "hydrillabugs")
+ ("www.hachettebugs" "" "IN" "CNAME" "hachettebugs")
+ ("haketilo" "" "IN" "CNAME" "salamina")
+ ("www.haketilo" "" "IN" "CNAME" "haketilo")
+ ("hydrilla" "" "IN" "CNAME" "salamina")
+ ("hydrillabugs" "" "IN" "CNAME" "salamina")
+ ("www.hydrillabugs" "" "IN" "CNAME" "hydrillabugs")
+ ("imap" "" "IN" "CNAME" "salamina")
+ ("ns1" "" "IN" "CNAME" "antioch")
+ ("ns2" "" "IN" "CNAME" "salamina")
+ ("pray" "" "IN" "CNAME" "salamina")
+ ("www.pray" "" "IN" "CNAME" "pray")
+ ("sheets" "" "IN" "CNAME" "salamina")
+ ("www.sheets" "" "IN" "CNAME" "sheets")
+ ("smtp" "" "IN" "CNAME" "salamina")
+
+ ;; mail
+ ("@" "" "IN" "MX 10" "smtp.koszko.org.")
+ ;; dmarc
+ ("@" "" "IN" "TXT" "\"v=spf1 ip4:188.68.236.76 ip4:188.68.237.248 -all\"")
+ ("_dmarc" "" "IN" "TXT" (format #f "\"~{~{~a=~a~}~^;~}\""
+ '(("v" "DMARC1")
+ ("p" "reject")
+ ("rua" "mailto:dmarc@koszko.org")
+ ("ruf" "mailto:dmarc@koszko.org")
+ ("rf" "afrf")
+ ("pct" "100"))))
+ ("mail-salamina._domainkey" "" "IN" "TXT" "(
+ \"k=rsa;t=s;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsC9HfcId\"
+ \"QGcBzYtBzv/VF7vPrRAASwfeAJ3pr0tddpYtFMGGm8kWPAKykX2LvP4epQPdzGL9\"
+ \"W9qLJk3R+iJSlUYLgP1s4Tr5qiUm/PEHPnjzwC8kqtJ/CrQs7WLfiuE3SElWI3iQ\"
+ \"FMRCD1Kk07axSOCgLbshthEAxZQqScYiZT7Irl4SHm9SpTUJkqh5xcCTqsW1yuG/\"
+ \"YWbfERH4PFp2pA85ZZvVEHqd+e8LMLh9EKMYRbhp9AVKMaESIegkO0RZv0KGp4aU\"
+ \"vzquG1FYQ9VOJ6KiviZANuEL4cpNrqmFb4Wbuwc6w7drWaHjFT/j1mS/eB0DN3el\"
+ \"nPQnWMTJZPhqnFZKzG37P5VkIDjbcotevsBGV28gx3VJNf1ye1x/P9f4fJw2s7EY\"
+ \"izNZx9/xfmAiOpP3KhrpE+cccBWnMHYyp0X7ClgBIQTDiLOBX3KhH+GOuADMcum1\"
+ \"4y8SHw2xSYGGk46YI0fBf8kaJsAA9wBQvuBFSj1MjxjdWt0GF0OLnGB1RsPZx+nU\"
+ \"Q+EZz0PDuv16ofN7MaOfY+kD6XoBCDjj4FDqLOgBgoLS7LfLyYTElbuItj12Yqph\"
+ \"ZPY4I+Lmn9nzl3tEnUqtRNu5LPhIR9mj/4BLp2UPgkVnqTAcA+qxoJghm8hh9AS9\"
+ \"2pelav0CarwwvUo09rcvujksuwy8TulK8ckCAwEAAQ==\"
+ )")
+
+ ((string-append domain "._report._dmarc") "" "IN" "TXT" "\"v=DMARC1\""))
+
+ entries)
+
+(dns:define-zone-entries %happyhacking.pl-zone-entries
+ ;; nameservers
+ ("@" "" "IN" "NS" "ns2.happyhacking.pl.")
+ ("@" "" "IN" "NS" "ns0.1984.is.")
+ ("@" "" "IN" "NS" "ns1.1984.is.")
+ ("@" "" "IN" "NS" "ns2.1984.is.")
+ ("@" "" "IN" "NS" "ns1.1984hosting.com.")
+ ("@" "" "IN" "NS" "ns2.1984hosting.com.")
+ ;; domain->IP assignments
+ ("ns1" "" "IN" "A" "188.68.236.76")
+ ("ns2" "" "IN" "A" "188.68.237.248")
+ ("@" "" "IN" "CNAME" "salamina.koszko.org")
+ ("www" "" "IN" "CNAME" "@")
+ ("git" "" "IN" "CNAME" "@")
+ ("www.git" "" "IN" "CNAME" "git")
+ ;; mail
+ ("@" "" "IN" "MX 10" "smtp.koszko.org.")
+ ("@" "" "IN" "TXT" "\"v=spf1 ip4:188.68.236.76 ip4:188.68.237.248 -all\"")
+ ("_dmarc" "" "IN" "TXT" (format #f "\"~{~{~a=~a~}~^;~}\""
+ '(("v" "DMARC1")
+ ("p" "reject")
+ ("rua" "mailto:dmarc@happyhacking.pl")
+ ("ruf" "mailto:dmarc@happyhacking.pl")
+ ("rf" "afrf")
+ ("pct" "100"))))
+ ("happyhacking.pl._report._dmarc" "" "IN" "TXT" "\"v=DMARC1\"")
+ ("mail-salamina._domainkey" "" "IN" "TXT" "(
+ \"k=rsa;t=s;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsC9HfcId\"
+ \"QGcBzYtBzv/VF7vPrRAASwfeAJ3pr0tddpYtFMGGm8kWPAKykX2LvP4epQPdzGL9\"
+ \"W9qLJk3R+iJSlUYLgP1s4Tr5qiUm/PEHPnjzwC8kqtJ/CrQs7WLfiuE3SElWI3iQ\"
+ \"FMRCD1Kk07axSOCgLbshthEAxZQqScYiZT7Irl4SHm9SpTUJkqh5xcCTqsW1yuG/\"
+ \"YWbfERH4PFp2pA85ZZvVEHqd+e8LMLh9EKMYRbhp9AVKMaESIegkO0RZv0KGp4aU\"
+ \"vzquG1FYQ9VOJ6KiviZANuEL4cpNrqmFb4Wbuwc6w7drWaHjFT/j1mS/eB0DN3el\"
+ \"nPQnWMTJZPhqnFZKzG37P5VkIDjbcotevsBGV28gx3VJNf1ye1x/P9f4fJw2s7EY\"
+ \"izNZx9/xfmAiOpP3KhrpE+cccBWnMHYyp0X7ClgBIQTDiLOBX3KhH+GOuADMcum1\"
+ \"4y8SHw2xSYGGk46YI0fBf8kaJsAA9wBQvuBFSj1MjxjdWt0GF0OLnGB1RsPZx+nU\"
+ \"Q+EZz0PDuv16ofN7MaOfY+kD6XoBCDjj4FDqLOgBgoLS7LfLyYTElbuItj12Yqph\"
+ \"ZPY4I+Lmn9nzl3tEnUqtRNu5LPhIR9mj/4BLp2UPgkVnqTAcA+qxoJghm8hh9AS9\"
+ \"2pelav0CarwwvUo09rcvujksuwy8TulK8ckCAwEAAQ==\"
+ )"))
+
+(prepend %services
+ (service dns:knot-service-type
+ (dns:knot-configuration
+ (acls (list (dns:knot-acl-configuration
+ (id "allow-axfr-from-1984")
+ (address '("93.95.224.6"))
+ (action '(transfer)))))
+
+ (remotes (list (dns:knot-remote-configuration
+ (id "1984-axfr-remote")
+ (address '("93.95.224.6")))))
+
+ (zones (cons* (dns:knot-zone-configuration
+ (domain "happyhacking.pl")
+ (zone (dns:zone-file
+ (origin "happyhacking.pl")
+ (entries %happyhacking.pl-zone-entries)
+ (ns "ns2")
+ (mail "hostmaster")
+ (serial 2024050300)))
+ (acl '("allow-axfr-from-1984"))
+ (semantic-checks? #t)
+ (notify '("1984-axfr-remote")))
+
+ (map (lambda (domain)
+ (dns:knot-zone-configuration
+ (domain domain)
+ (zone (dns:zone-file
+ (origin domain)
+ (entries (make-koszko-zone-entries domain))
+ (ns "ns2")
+ (mail "koszko")
+ (serial 2024050301)))
+ (acl '("allow-axfr-from-1984"))
+ (semantic-checks? #t)
+ (notify '("1984-axfr-remote"))))
+ '("koszko.org" "koszkonutek-tmp.pl.eu.org")))))))
+
+(prepend %services
+ (service mail:mail-aliases-service-type
+ '(("root" "admin"))))
+
+(prepend %services
+ (service mail:exim-service-type
+ (mail:exim-configuration
+ (config-file (local-file "./exim.conf"))
+ (setuid-user 0))))
+
+(prepend %services
+ (simple-service 'make-maildirs-directory activation-service-type
+ #~(begin
+ (mkdir-p "/var/vmail")
+ (let ((initial-umask (umask)))
+ (umask #o007)
+ (mkdir-p "/var/vmail/maildirs")
+ (chown "/var/vmail/maildirs" -1 (group:gid (getgr "vmail")))
+ (umask initial-umask)))))
+
+(prepend %services
+ (service mail:dovecot-service-type
+ (mail:dovecot-configuration
+ (services (list (mail:service-configuration
+ (kind "imap-login")
+ (listeners (list (mail:inet-listener-configuration
+ (protocol "imaps")
+ (port 993)
+ (ssl? #t))))
+ ;; '1' is more secure than '0' because each
+ ;; connection is handled in a separate process.
+ (service-count 1))
+ (mail:service-configuration
+ (kind "imap"))
+ (mail:service-configuration
+ (kind "auth")
+ (listeners (list (mail:unix-listener-configuration
+ (path "auth-userdb"))))
+ ;; Dovecot requires process-limit to be 1 here.
+ (service-count 0)
+ (process-limit 1))))
+ (ssl-cert "</etc/certs/imap.koszko.org/fullchain.pem")
+ (ssl-key "</etc/certs/imap.koszko.org/privkey.pem")
+ (auth-mechanisms '("plain" "login"))
+ (passdbs (list (mail:passdb-configuration
+ (driver "passwd-file")
+ (args '("scheme=SHA256-CRYPT"
+ "username_format=%u"
+ "/var/vmail/passwd")))))
+ (userdbs (list (mail:userdb-configuration
+ (driver "static")
+ (args '("home=/var/vmail/maildirs/%n")))))
+ (mail-uid "vmail")
+ (mail-gid "vmail")
+ (mail-location "maildir:/var/vmail/maildirs/%n"))))
+
+(prepend %services
+ (service openssh-service-type
+ (openssh-configuration
+ (permit-root-login 'prohibit-password)
+ (authorized-keys `(("root" ,(local-file "koszko.pub"))))
+ (port-number 10022))))
+
+(prepend %services
+ (service vc:gitolite-service-type
+ (vc:gitolite-configuration
+ (admin-pubkey (local-file "koszko.pub"))
+ (rc-file (vc:gitolite-rc-file
+ (umask #o027)
+ (git-config-keys ".*")
+ (enable '("help"
+ "desc"
+ "info"
+ "perms"
+ "writable"
+ "ssh-authkeys"
+ "git-config"
+ "daemon"
+ "gitweb"
+ "cgit")))))))
+
+(prepend %services
+ (service postgresql-service-type
+ (postgresql-configuration (port 15432))))
+
+(operating-system
+ (host-name "salamina")
+ (timezone "Europe/Warsaw")
+ (locale "en_US.utf8")
+
+ (keyboard-layout (keyboard-layout "pl"))
+
+ (bootloader (bootloader-configuration
+ (bootloader grub-bootloader)
+ (targets '("/dev/vda"))))
+
+ (users (cons* (gss:user-account
+ (name "vmail")
+ (group "vmail")
+ (system? #t)
+ (comment "Email access user")
+ (home-directory "/var/empty")
+ (shell (file-append shadow "/sbin/nologin")))
+ (gss:user-account
+ (name "minetest")
+ (group "minetest")
+ (system? #t)
+ (comment "Minetest server")
+ (home-directory "/var/minetest")
+ (shell (file-append shadow "/sbin/nologin")))
+ gss:%base-user-accounts))
+
+ (groups (cons* (gss:user-group
+ (name "vmail")
+ (system? #t))
+ (gss:user-group
+ (name "minetest")
+ (system? #t))
+ (gss:user-group
+ (name "smtp-certificates")
+ (system? #t))
+ gss:%base-groups))
+
+ (extra-groups (list (gss:user-extra-groups
+ (user "exim")
+ (groups '("smtp-certificates")))
+ (gss:user-extra-groups
+ (user "httpd")
+ (groups '("git")))))
+
+ (file-systems (cons* (fs:file-system
+ (device (fs:file-system-label "salamina-root"))
+ (mount-point "/")
+ (type "ext4"))
+ fs:%base-file-systems))
+
+ (packages (append (specifications->packages
+ '("nss-certs"
+ "file"
+ "bind:utils"
+ "net-tools"
+ "man-pages-posix"
+ "emacs"
+ "minetest"))
+ %base-packages))
+
+ (services %services))
+
+;;; Local Variables:
+;;; eval: (put 'prepend 'scheme-indent-function 1)
+;;; End: