diff options
| author | winter Sparkles | 2026-08-04 19:18:37 +0100 |
|---|---|---|
| committer | winter Sparkles | 2026-08-04 19:18:37 +0100 |
| commit | 3c37b1b00f9d345ad1d036c8ef6a04cf633d3f5f (patch) | |
| tree | 1cc1c64170e6e53c5ccd7615906f94c237ebf80a | |
initial commit
| -rw-r--r-- | .gitignore | 11 | ||||
| -rw-r--r-- | Makefile | 16 | ||||
| -rw-r--r-- | README.org | 8 | ||||
| -rwxr-xr-x | batch-export | 11 | ||||
| -rwxr-xr-x | batch-tangle | 10 | ||||
| -rw-r--r-- | config.org | 200 | ||||
| -rwxr-xr-x | run-install-scripts | 4 |
7 files changed, 260 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9372290 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# tangled config files +sys/ + +# tangled scripts +scripts/ + +# distrib bundle +*.tar.xz + +# exported pages +*.html diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0ed3e43 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +all: tangle + +distrib.tar.xz: tangle + tar -c . | xz > $@ + +tangle: config.org + ./batch-tangle $^ + +config.html: config.org + ./batch-export $^ + +install: tangle + cp -aiuv sys/* / + ./run-install-scripts + +.PHONY: all tangle diff --git a/README.org b/README.org new file mode 100644 index 0000000..3f226ad --- /dev/null +++ b/README.org @@ -0,0 +1,8 @@ +#+title: Literate server config +#+author: winter Sparkles + +In this repository is a work-in-progress recreation of our main server +celestine's system and package configuration, using a 'literate' Org-Babel file. + +See [[file:config.org]], or run =make config.html= and open config.html in your +browser. diff --git a/batch-export b/batch-export new file mode 100755 index 0000000..8a617c9 --- /dev/null +++ b/batch-export @@ -0,0 +1,11 @@ +#!/bin/sh +# Export files with Org mode +# +emacs -q --batch --eval " + (progn + (require 'ox-html) + (setq org-html-htmlize-output-type 'css) + (dolist (file command-line-args-left) + (with-current-buffer (find-file-noselect file) + (org-html-export-to-html)))) + " "$@" diff --git a/batch-tangle b/batch-tangle new file mode 100755 index 0000000..93129da --- /dev/null +++ b/batch-tangle @@ -0,0 +1,10 @@ +#!/bin/sh +# Tangle files with Org mode +# +emacs -Q --batch --eval " + (progn + (require 'ob-tangle) + (dolist (file command-line-args-left) + (with-current-buffer (find-file-noselect file) + (org-babel-tangle)))) + " "$@" diff --git a/config.org b/config.org new file mode 100644 index 0000000..c595a17 --- /dev/null +++ b/config.org @@ -0,0 +1,200 @@ +#+title: Server configuration +#+author: winter Sparkles +#+property: header-args :mkdirp yes :padline no + +This is a work-in-progress recreation of our server's configuration in the form +of a literate Org file, plus a makefile that installs it for you. + +To use it, you can run =make && doas make install= on an existing Alpine system +that has (GNU) Emacs installed, or, you can run =make distrib.tar.xz= on some +other system with Emacs, then move the file =distrib.tar.xz= to an Alpine +system, unpack it over there, and run =doas make install=, which doesn't require +Emacs to be available on the target system. + +* Package management + +** apk repositories + +We're using the default CDN mirror (change this if you want a different one): +#+begin_src plain :noweb-ref apk-mirror + http://dl-cdn.alpinelinux.org/alpine +#+end_src + +The standard main and community repos for the latest stable release: +#+begin_src conf :tangle sys/etc/apk/repositories :noweb yes + <<apk-mirror>>/latest-stable/main + <<apk-mirror>>/latest-stable/community +#+end_src + +Plus, extra ones for community and testing on the edge branch, to allow +installing more software and newer versions of certain packages: +#+begin_src conf :tangle sys/etc/apk/repositories :noweb yes + @community-edge <<apk-mirror>>/edge/community + @testing <<apk-mirror>>/edge/testing +#+end_src + +* System utilities + +** cron daemon + +We're just using the busybox cron daemon, it gets the job done. +#+begin_src shell :tangle scripts/enable-services + rc-update add crond +#+end_src + +By default, the system comes with a crontab that executes scripts under +=/etc/periodic/<interval>= every so often. + +* Networking + +** tinc VPN + +TODO + +** DNS + +#+begin_src conf :tangle sys/etc/resolvconf.conf :exports none + resolv_conf=/etc/resolv.conf +#+end_src + +We run a local DNS server, which uses unbound, therefore install and enable +unbound: +#+begin_src conf :tangle sys/etc/apk/world + unbound + unbound-doc +#+end_src +#+begin_src shell :tangle scripts/enable-services :tangle-mode o755 :shebang #!/bin/sh + rc-update add unbound +#+end_src + +Point the system resolver at the unbound server (in resolvconf.conf): +#+begin_src conf :tangle sys/etc/resolvconf.conf + name_servers=127.0.0.1 +#+end_src + +*** Authoritative zone for internal VPN addresses + +Since we use [[*tinc VPN][tinc mesh VPN]], all of our machines have internal IP addresses, and +it's nice have them be resolvable by their hostnames. + +So there is this zonefile: +#+begin_src zone :tangle sys/etc/unbound/zones/infra.zone + $ORIGIN infra.xn--80andq.net. + $TTL 3600 + + @ IN SOA celestine.infra.xn--80andq.net. contact.xn--80andq.net. 2026072202 10800 3600 604800 3600 + + amber.infra.xn--80andq.net. IN AAAA fd8c:4ea1:9a24:1::4 + amber.infra.xn--80andq.net. IN A 10.101.1.4 + neptunite.infra.xn--80andq.net. IN AAAA fd8c:4ea1:9a24:1::5 + neptunite.infra.xn--80andq.net. IN A 10.101.1.5 + selenite.infra.xn--80andq.net. IN AAAA fd8c:4ea1:9a24:1::2 + selenite.infra.xn--80andq.net. IN A 10.101.1.2 + celestine.infra.xn--80andq.net. IN AAAA fd8c:4ea1:9a24:1::1 + celestine.infra.xn--80andq.net. IN A 10.101.1.1 + ametrine.infra.xn--80andq.net. IN AAAA fd8c:4ea1:9a24:1::3 + ametrine.infra.xn--80andq.net. IN A 10.101.1.3 +#+end_src + +unbound also needs to be told about it: +#+begin_src conf :tangle sys/etc/unbound/unbound.conf.d/authority.conf + auth-zone: + name: infra.xn--80andq.net. + zonefile: /etc/unbound/zones/infra.zone +#+end_src + +Finally, resolvconf can be told about it as a 'search domain' so it's possible +to just write the short hostnames: +#+begin_src conf :tangle sys/etc/resolvconf.conf + search_domains=infra.xn--80andq.net +#+end_src + +*** More miscellaneous unbound config snippets +**** Be accessible on the appropriate interfaces + +Again, this is necessary because we want unbound to be visible to other devices +in the tinc network. +#+begin_src conf :tangle sys/etc/unbound/unbound.conf.d/interfaces.conf + server: + interface: winternet + interface: lo + access-control: 10.101.0.0/16 allow + access-control: 127.0.0.1 allow +#+end_src + +**** Recursively resolve upstream zones + +Here we're using the 9.9.9.9 public recursive DNS server. +#+begin_src conf :tangle sys/etc/unbound/unbound.conf.d/upstream.conf + forward-zone: + name: "." + forward-addr: 9.9.9.9 +#+end_src + +**** Rehike +TODO: move this section to the actual section for rehike, whenever we write that + +#+begin_src conf :tangle sys/etc/unbound/unbound.conf.d/youtube.conf + server: + local-zone: "youtube.com." redirect + local-data: "youtube.com. A 10.101.1.1" +#+end_src + +** TLS certificates + +*** Let's Encrypt + +Obviously we can't put the full and entire configuration here because it might +let you impersonate us. But! Here are some parts: + +We're using certbot because we're lazy, and also the PowerDNS plugin for it so +that we can use it with [[https://servfail.network/][servfail]]: +#+begin_src conf :tangle sys/etc/apk/world + certbot + certbot-dns-pdns@testing +#+end_src + +Then, after getting certificates for the first time (consult certbot docs on how +to do that), this script in =/etc/periodic/weekly= makes sure they're renewed as +needed, and informs us when it does so using [[*sendmail-fancy][sendmail-fancy]]: +#+begin_src shell :tangle sys/etc/periodic/weekly/certbot-renew.sh :tangle-mode o755 + #!/bin/bash + { + printf "it's that time of the week again...\n\n" + certbot renew + } | sendmail-fancy crond@celestine winter "certbot renew output" +#+end_src + +** Email + +We use [[https://www.opensmtpd.org/][OpenSMTPD]] as an email server, since it's easy to configure. Plus the +dkimsign filter for it, to allow signing outbound emails with our DKIM key. +#+begin_src conf :tangle sys/etc/apk/world + opensmtpd + opensmtpd-doc + opensmtpd-filter-dkimsign + opensmtpd-filter-dkimsign-doc +#+end_src + +TODO: smtpd config and dovecot config + +*** sendmail-fancy + +Super simple shell script that makes it easier to send emails programmatically: +#+begin_src shell :tangle sys/usr/local/bin/sendmail-fancy + #!/bin/bash + + if [ $# -ne 3 ]; then + echo "usage: $0 <sender> <recipient> <subject>" 1>&2 + exit 1 + fi + + { + echo "Subject: $3" + echo "To: $2" + echo "From: $1" + echo "Date: $(date -R)" + echo + cat + } | sendmail -t +#+end_src diff --git a/run-install-scripts b/run-install-scripts new file mode 100755 index 0000000..7e6b9e1 --- /dev/null +++ b/run-install-scripts @@ -0,0 +1,4 @@ +#!/bin/sh +for f in scripts/*; do + "$f" +done |
