Compare commits

..

96 Commits

Author SHA1 Message Date
joeac 5d849384bc chown tls_certs 2026-07-07 10:27:10 +01:00
joeac 5e640711ce fix cert-name in tls.mk 2026-07-07 10:22:32 +01:00
joeac 44e4605be8 adds install_tls rule 2026-07-07 10:11:01 +01:00
joeac 60ba3328fa improves certbot cmds 2026-07-07 10:07:17 +01:00
joeac 5a5301fefb fixes certonly command 2026-07-07 10:06:33 +01:00
joeac 4ee7c34161 mox depends on tls certs 2026-07-07 09:53:24 +01:00
joeac fe1d19a9c7 mox/reinstall 2026-07-07 09:49:24 +01:00
joeac 6d8541f052 install tls_domain, not tls_module 2026-07-07 09:48:09 +01:00
joeac ba2359f8b9 again 2026-07-07 09:41:35 +01:00
joeac 9ef09754be fix renew rule call 2026-07-07 09:37:48 +01:00
joeac cbe223166e certbot delete is non-interactive 2026-07-07 09:35:42 +01:00
joeac fb2785f694 again 2026-07-07 09:34:55 +01:00
joeac f9dcf157a0 fix delete_cert for real this time 2026-07-07 09:33:13 +01:00
joeac 83a482de03 fix syntax in delete_cert rule call 2026-07-07 09:30:11 +01:00
joeac 208f383925 if master node, install all subdomains, else none 2026-07-07 09:28:21 +01:00
joeac 05f9535a9b tls.mk: remove 'test' 2026-07-07 09:23:02 +01:00
joeac c18fd9c44e tls.mk: subdomains, not modules 2026-07-07 09:20:06 +01:00
joeac 07fa302d43 tls.mk 2026-07-07 09:10:58 +01:00
joeac 4a2b27f54a microlog post 2026-07-06 2026-07-06 12:58:25 +01:00
joeac ff507ea16a adds conf to mox deps 2026-07-05 23:23:01 +01:00
joeac 639196f0c9 install mox config 2026-07-05 23:18:11 +01:00
joeac 404cb2d98c also dirs != ordinary files 2026-07-05 23:08:02 +01:00
joeac 665d808660 fix case in last two commits 2026-07-05 23:06:29 +01:00
joeac 15027fef29 ditto, and fix dir 2026-07-05 23:05:18 +01:00
joeac 26ae12f638 calcs gemini_user in make, not shell 2026-07-05 23:04:09 +01:00
joeac 56393380b9 only make .env if dir exists 2026-07-05 23:01:56 +01:00
joeac d51d1a1266 adds mox_clientsettings to blade-canongate 2026-07-05 22:59:42 +01:00
joeac af5599ba54 missed a - 2026-07-05 22:58:57 +01:00
joeac ce8017c6d2 remove ref to removed install_dyndns rule 2026-07-05 22:47:45 +01:00
joeac b64f8ddffa replaces - with _ in vars 2026-07-05 22:30:21 +01:00
joeac e926d562c0 adds mox ports 2026-07-05 22:29:03 +01:00
joeac 064adbc0b7 adds mox sub-subdomains 2026-07-05 22:28:53 +01:00
joeac 4872b95c43 cp, not mv, resolv.conf 2026-07-05 16:30:24 +01:00
joeac 4547dd5681 unbound-anchor requires sudo 2026-07-05 16:27:06 +01:00
joeac 655ac1404a fix /etc/resolv.conf.joeac.net-backup rule 2026-07-05 16:24:12 +01:00
joeac 521d768635 adds mox 2026-07-05 16:09:20 +01:00
joeac f736c46b81 defines openrc rules for all modules (so they can be uninstalled) 2026-07-04 20:13:36 +01:00
joeac f537b99d02 uses IMAGE_PREFIX var in gemini.Dockerfile 2026-07-04 20:12:04 +01:00
joeac ad4b03871e moves container.mk vars to vars.mk so that IMAGE_PREFIX is defined
before it is used in COMPOSE_CMD
2026-07-04 20:11:07 +01:00
joeac 4ef4bbd4ad gives gemini pi-broughton -> blade-canongate 2026-07-04 20:02:02 +01:00
joeac 2e44bfa09a remove nginx site requires sudo 2026-07-04 14:25:49 +01:00
joeac 424b4c6971 uses ip addr instead of hostname to simplify dns config 2026-07-04 14:18:42 +01:00
joeac 4130448a55 swaps master node to blade-canongate 2026-07-04 08:43:00 +01:00
joeac ed6a6e5a34 update.sh exports XDG_RUNTIME_DIR 2026-07-03 16:29:17 +01:00
joeac 36ccd48cfc fix dollars in static.conf.template getting removed 2026-07-03 16:23:01 +01:00
joeac 61f2b376ee chown /var dirs 2026-07-03 16:02:05 +01:00
joeac b59888dc99 splits sudo to avoid env confusion 2026-07-03 15:50:14 +01:00
joeac d29e120c72 ...but for real this time 2026-07-03 15:40:15 +01:00
joeac 16cc43ad28 fix bin/pp again? 2026-07-03 15:37:36 +01:00
joeac 3773af632c fix bin/pp rule 2026-07-03 15:34:19 +01:00
joeac 2aeb58d9ed no quotes around COMPOSECMD 2026-07-03 15:23:13 +01:00
joeac affc7521d6 chmod +x for joeac.net openrc service 2026-07-03 15:21:41 +01:00
joeac f5a7d78d4f uses custom COMPOSECMD in joeac.net openrc services 2026-07-03 15:14:02 +01:00
joeac c42c636231 splits sudo to avoid env confusion 2026-07-03 15:08:46 +01:00
joeac 99b21dbe8e stores src in $HOME and more perm tweaks 2026-07-03 15:01:48 +01:00
joeac 3af4546839 adds XDG_RUNTIME_DIR explicitly in update.sh 2026-07-03 13:38:21 +01:00
joeac ace7801796 typo in openrc.mk: joeac.net.$(module) 2026-07-03 13:23:20 +01:00
joeac 7d0a920c8c provides ETHERPAD_VERSION in vars.mk 2026-07-03 12:37:02 +01:00
joeac f24f1ff4b7 provides ALPINE_VERSION in vars.mk 2026-07-03 12:31:49 +01:00
joeac 703359301b envsubst uses -io flags instead of positional params 2026-07-03 12:29:31 +01:00
joeac 66da50eb92 logins back in after updating groups 2026-07-03 12:27:50 +01:00
joeac 757a24894a chmod 770 on /home/joeac.net 2026-07-03 12:20:24 +01:00
joeac 4b19aabba6 chmod on .env 2026-07-03 12:14:02 +01:00
joeac 626642cd25 get_var_value 2026-07-03 12:12:25 +01:00
joeac a1c91da619 set +e install.sh 2026-07-03 12:07:05 +01:00
joeac fac4169389 removes CONTAINER_PREFIX from example.env (redundant) 2026-07-03 12:06:34 +01:00
joeac a5f1ea1358 copes with empty var values 2026-07-03 12:05:45 +01:00
joeac db8df130fe removes ^ from expr for portability 2026-07-03 12:02:38 +01:00
joeac 52f4ab3157 more portable conditon 2026-07-03 12:00:02 +01:00
joeac 8519d854fb expr has : 2026-07-03 11:51:16 +01:00
joeac edd01e4445 absolutely provides dir to make in install.sh 2026-07-03 11:47:05 +01:00
joeac 9ea2820411 absolutises example.env 2026-07-03 11:46:36 +01:00
joeac 967818f315 absolute chown /home/jeoac.net/joeac.net 2026-07-03 11:45:43 +01:00
joeac ca8e06f300 Merge branch 'main' of https://git.joeac.net/joeac/joeac.net 2026-07-03 11:44:50 +01:00
joeac a611b5010f another attempt to fix perms 2026-07-03 11:44:22 +01:00
joeac 2bc353c8fc install.sh gives rw permissions to user over repo using groups 2026-07-03 11:41:00 +01:00
joeac d4dd979311 install.sh gives rw permissions to user over repo using groups 2026-07-03 11:39:27 +01:00
joeac cd4bafbed3 install.sh: no password for joeac.net user 2026-07-03 11:22:56 +01:00
joeac 51d7222c84 install.sh: adds missing joeac/ in repo URL 2026-07-03 11:21:25 +01:00
joeac 888df5c664 install.sh: replaces doas with sudo 2026-07-03 11:20:36 +01:00
joeac 220394ed0d don't set -x in install.sh 2026-07-03 11:19:26 +01:00
joeac 89280d6087 install.sh: wget to /usr requires doas 2026-07-03 11:19:01 +01:00
joeac cb3ad780b1 install.sh: chmod +x in /usr needs doas 2026-07-03 11:17:46 +01:00
joeac 9615c940bb specifies explicit ENVSUBST_VERSION if wget from github 2026-07-03 11:17:17 +01:00
joeac 33e0fb21d6 set -x in install.sh 2026-07-03 11:15:10 +01:00
joeac 2a8b2b3a40 install.sh specifies latest version of envsubst when installing with go
install
2026-07-03 11:11:43 +01:00
joeac f765e1d38f go get -> go install 2026-07-03 11:06:21 +01:00
joeac e6c011d007 removes extraneous " in install.sh 2026-07-03 11:04:37 +01:00
joeac ba8aaa4ade removes redundant README stuff 2026-07-03 11:04:00 +01:00
joeac 9a93c6f983 install.sh installs dependencies 2026-07-03 11:03:36 +01:00
joeac 803e9e00e0 install.sh picks up where left off with env vars 2026-07-03 10:49:19 +01:00
joeac bb795a9555 install.sh picks up with cloning where left off 2026-07-03 10:46:58 +01:00
joeac ac81aeed31 install.sh doesn't attempt to re-add joeac.net user if already exists 2026-07-03 10:44:52 +01:00
joeac 6a4d6d88c5 install.sh creates remote_smtp_password 2026-07-03 10:41:08 +01:00
joeac 32ae7e2b38 checks for some dependencies in install.sh 2026-07-03 10:35:44 +01:00
joeac 4e62da3d52 installs etherpad data dir 2026-07-03 10:29:34 +01:00
27 changed files with 634 additions and 184 deletions
+7 -6
View File
@@ -17,19 +17,19 @@ endef
define install_module_rule = define install_module_rule =
.PHONY: install_$(module) .PHONY: install_$(module)
install_$(module): install_openrc_$(module) install_dyndns_$(module) $(install_submake_file) install_$(module): install_openrc_$(module) install_dyndns_$(module) $(if $(SUBDOMAIN_$(module)),install_tls_$(SUBDOMAIN_$(module))) $(install_submake_file)
$(if $(install_submake_file),$(MAKE) --makefile=$(notdir $(install_submake_file)) --directory=$(dir $(install_submake_file)) install) $(if $(install_submake_file),$(MAKE) --makefile=$(notdir $(install_submake_file)) --directory=$(dir $(install_submake_file)) install)
endef endef
define reinstall_module_rule = define reinstall_module_rule =
.PHONY: reinstall_$(module) .PHONY: reinstall_$(module)
reinstall_$(module): reinstall_openrc_$(module) reinstall_dyndns_$(module) $(install_submake_file) reinstall_$(module): reinstall_openrc_$(module) reinstall_dyndns_$(module) $(if $(SUBDOMAIN_$(module)),reinstall_tls_$(SUBDOMAIN_$(module))) $(install_submake_file)
$(if $(install_submake_file),$(MAKE) --makefile=$(notdir $(install_submake_file)) --directory=$(dir $(install_submake_file)) reinstall) $(if $(install_submake_file),$(MAKE) --makefile=$(notdir $(install_submake_file)) --directory=$(dir $(install_submake_file)) reinstall)
endef endef
define uninstall_module_rule = define uninstall_module_rule =
.PHONY: uninstall_$(module) .PHONY: uninstall_$(module)
uninstall_$(module): uninstall_openrc_$(module) uninstall_dyndns_$(module) uninstall_$(module): uninstall_openrc_$(module) uninstall_dyndns_$(module) $(if $(SUBDOMAIN_$(module)),install_tls_$(SUBDOMAIN_$(module)))
$(if $(install_submake_file),\ $(if $(install_submake_file),\
$(MAKE) --makefile=$(notdir $(install_submake_file)) --directory $(dir $(install_submake_file)) uninstall $(MAKE) --makefile=$(notdir $(install_submake_file)) --directory $(dir $(install_submake_file)) uninstall
) )
@@ -42,13 +42,13 @@ $(foreach module,$(ALL_MODULES),$(eval $(call make_module_rule)))
$(foreach module,$(ALL_MODULES),$(eval $(call module_env_rule))) $(foreach module,$(ALL_MODULES),$(eval $(call module_env_rule)))
.PHONY: install .PHONY: install
install: install_nginx $(ENV_RULES) $(INSTALL_RULES) install_crontab install: install_nginx install_tls $(ENV_RULES) $(INSTALL_RULES) install_crontab
.PHONY: reinstall .PHONY: reinstall
reinstall: reinstall_nginx reinstall_dyndns $(ENV_RULES) $(REINSTALL_RULES) reinstall_crontab reinstall: reinstall_nginx reinstall_dyndns reinstall_tls $(ENV_RULES) $(REINSTALL_RULES) reinstall_crontab
.PHONY: uninstall .PHONY: uninstall
uninstall: uninstall_nginx uninstall_dyndns uninstall_joeac.net_service $(UNINSTALL_RULES) uninstall_crontab uninstall: uninstall_nginx uninstall_dyndns uninstall_tls uninstall_joeac.net_service $(UNINSTALL_RULES) uninstall_crontab
$(foreach module,$(ALL_MODULES),$(eval $(install_module_rule))) $(foreach module,$(ALL_MODULES),$(eval $(install_module_rule)))
$(foreach module,$(ALL_MODULES),$(eval $(reinstall_module_rule))) $(foreach module,$(ALL_MODULES),$(eval $(reinstall_module_rule)))
@@ -63,3 +63,4 @@ include make/openrc.mk
include make/nginx.mk include make/nginx.mk
include make/crontab.mk include make/crontab.mk
include make/dyndns.mk include make/dyndns.mk
include make/tls.mk
+81 -28
View File
@@ -8,44 +8,97 @@ To install:
wget -O- https://git.joeac.net/joeac/joeac.net/raw/branch/main/install.sh | sh wget -O- https://git.joeac.net/joeac/joeac.net/raw/branch/main/install.sh | sh
``` ```
Structure: ## DNS setup
A/AAAA DNS records are added automatically by `make install`, but in order to
get `mox` working as an email server, you'll have to manually add the following
DNS records.
Deliver mail for mail.joeac.net to mail.joeac.net:
``` ```
/ mail.joeac.net. MX 10 mail.joeac.net.
├── gemini My Gemini capsule
├── smtp A local SMTP server
└── http My Website
``` ```
## Running with Podman All emails from the email server will be signed with two DKIM keys. So that
clients can verify the authenticity of the messages, provide these keys as TXT
records:
These instructions will probably work with Docker, too: just substitute `podman` ```
for `docker` in all the commands. 2026a._domainkey.mail.joeac.net. TXT v=DKIM1;h=sha256;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvYfjrzmYgBtYofzBwI80aiW98+M2g6z+gd1Iwz9g0y30rPFNTctFn9GwBNuYBgZiZxB+sqjEbPMbr3li/R7i0A9t/KbNNJhkNC+4IjKJjk+jw1CXm4vXOUa4YSYWwy7NVYTH/QwZGz6fwjVM7YvDnnE4gG2NwrVx+AXlONt2R1G+qgV6HAIIvVi8T0yCjjqEc5B5bKlqk0XU9vSyUFJhhKnR/KNRe79C+H9GWJzcU7HUCmIHX04Xi0JeB/wm3weF1xjtGTsWyy5BmHHsfWGqSr2Dbg5o6AI5W0h4VkQ4QzdEYGVQ9ZBDyqFQwQFXLn0oHZjCD/vFzPOPdM5pxF/OgwIDAQAB
2026b._domainkey.mail.joeac.net. TXT v=DKIM1;h=sha256;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzcrk9FUt6AdrvnAP3KawuOTLw7uL5SJ+ZYmShuz41zwM6bPQteGSSwddFXIxcqVlJrdFahrK4KvHX/sw/hWVfZoPLDdwsGN5eI8cqQjNDE+JDu9BbPlTituva4Hkve0hbAKDqA8jmbcZg6aU7b44Kzq8UpWAlPO273Rq2tsbCBcITt8B3NFoeY9CSsZU1LqGl855GUtaNyhlPaAvfab3Q9/4wyusPhCHlBYaRK+ZzuSMs5KEOG6n4kbZfMVi2+4c/bPU5PdTuyvbSIEqjNH4TpfatE0I9ubGv0WbAzr5EZbv5+xtukZ/dIisPPMjn1AbjpSJYNYr2OYgey6+WvzRmQIDAQAB
To run with Podman, first set up your environment variables. Copy `example.env`
to `.env` and edit the values accordingly.
Then, create the `remote_smtp_password` secret, storing the password for the
remote SMTP server which will send the contact emails on behalf of the website.
```bash
sudo podman secret create remote_smtp_password /path/to/remote/smtp/password
``` ```
Now build and start the containers: Specify the MX host is allowed to send for our domain and for itself (for DSNs).
~all means softfail for anything else, which is done instead of -all to prevent
older mail servers from rejecting the message because they never get to looking
for a dkim/dmarc pass.
```bash ```
sudo podman-compose build && sudo podman-compose up -d mail.joeac.net. TXT v=spf1 ip4:217.155.190.42 ip6:fdc9:6aec:7a18:0:2e0:4cff:fe61:9b17 mx ~all
``` ```
## Running on the host machine Emails that fail the DMARC check (without aligned DKIM and without aligned SPF)
should be rejected, and request reports. If you email through mailing lists that
strip DKIM-Signature headers and don't rewrite the From header, you may want to
set the policy to p=none.
To run on the host machine, first, as before, set up your environment variables ```
by copying `example.env` to `.env` and editing the values as appropriate. _dmarc.mail.joeac.net. TXT v=DMARC1;p=reject;rua=mailto:dmarcreports@mail.joeac.net!10m
```bash
npm run start
``` ```
Note that emails may not work locally without further setup. These instructions Remote servers can use MTA-STS to verify our TLS certificate with the WebPKI
are of course woefully incomplete. pool of CA's (certificate authorities) when delivering over SMTP with
STARTTLSTLS.
```
mta-sts.mail.joeac.net. CNAME mail.joeac.net.
_mta-sts.mail.joeac.net. TXT v=STSv1; id=20260705T153220
```
Request reporting about TLS failures.
```
_smtp._tls.mail.joeac.net. TXT v=TLSRPTv1; rua=mailto:tlsreports@mail.joeac.net
```
Client settings will reference a subdomain of the hosted domain, making it
easier to migrate to a different server in the future by not requiring settings
in all clients to be updated.
```
clientsettings.mail.joeac.net. CNAME mail.joeac.net.
```
Autoconfig is used by Thunderbird. Autodiscover is (in theory) used by
Microsoft.
```
autoconfig.mail.joeac.net. CNAME mail.joeac.net.
_autodiscover._tcp.mail.joeac.net. SRV 0 1 443 mail.joeac.net.
```
For secure IMAP and submission autoconfig, point to mail host.
```
_imaps._tcp.mail.joeac.net. SRV 0 1 993 mail.joeac.net.
_submissions._tcp.mail.joeac.net. SRV 0 1 465 mail.joeac.net.
```
Next records specify POP3 and non-TLS ports are not to be used. These are
optional and safe to leave out (e.g. if you have to click a lot in a DNS admin
web interface).
```
_imap._tcp.mail.joeac.net. SRV 0 0 0 .
_submission._tcp.mail.joeac.net. SRV 0 0 0 .
_pop3._tcp.mail.joeac.net. SRV 0 0 0 .
_pop3s._tcp.mail.joeac.net. SRV 0 0 0 .
```
Optional: You could mark Let's Encrypt as the only Certificate Authority allowed
to sign TLS certificates for your domain.
```
mail.joeac.net. CAA 0 issue "letsencrypt.org"
```
+3
View File
@@ -0,0 +1,3 @@
I've been following Ink and Switch's blog for a while. They're working creatively with computers. This is a great discussion about LLMs which covers what they are, how they are being abused to de-humanise the world, and how things could be different, concluding in a call for 'punk computing.' Let's have it!
=> https://www.inkandswitch.com/tangents/artificial/ Artificial | Ink and Switch
+13
View File
@@ -0,0 +1,13 @@
.PHONY: install
install: $(ETHERPAD_DATA_DIR)
.PHONY: reinstall
reinstall: $(ETHERPAD_DATA_DIR)
$(ETHERPAD_DATA_DIR):
sudo mkdir -p $(ETHERPAD_DATA_DIR)
ETHERPAD_USER=$(whoami) && sudo chown $$ETHERPAD_USER:$$ETHERPAD_USER $(ETHERPAD_DATA_DIR)
.PHONY: uninstall
uninstall:
$(info Nothing to do)
-4
View File
@@ -1,7 +1,3 @@
# A prefix for remote container names
# If you're running on ARM 32-bit CPU architecture, use 'armv7/', otherwise keep blank
CONTAINER_PREFIX=
# The hostname to use for the local SMTP server # The hostname to use for the local SMTP server
LOCAL_SMTP_HOST=smtp LOCAL_SMTP_HOST=smtp
+3 -3
View File
@@ -1,6 +1,6 @@
FROM git.joeac.net/joeac/armv7/agate:3.3.20-alpine3.23 AS agate FROM git.joeac.net/joeac/${IMAGE_PREFIX}agate:3.3.20-alpine3.23 AS agate
FROM git.joeac.net/joeac/armv7/comitium:1.8.2-alpine3.23 AS comitium FROM git.joeac.net/joeac/${IMAGE_PREFIX}comitium:1.8.2-alpine3.23 AS comitium
FROM git.joeac.net/joeac/armv7/crond:1.37.0-r30-alpine3.23 AS final FROM git.joeac.net/joeac/${IMAGE_PREFIX}crond:1.37.0-r30-alpine3.23 AS final
RUN apk --no-cache add gcc # dependency for agate RUN apk --no-cache add gcc # dependency for agate
COPY --from=agate /root/.cargo/bin/agate /usr/local/bin/agate COPY --from=agate /root/.cargo/bin/agate /usr/local/bin/agate
COPY --from=comitium /usr/local/bin/comitium /usr/local/bin/comitium COPY --from=comitium /usr/local/bin/comitium /usr/local/bin/comitium
+2
View File
@@ -8,9 +8,11 @@ reinstall: $(GEMINI_CERTIFICATES_DIR) $(GEMINI_COMITIUM_DATA_FILES)
$(GEMINI_CERTIFICATES_DIR): $(GEMINI_CERTIFICATES_DIR):
sudo mkdir -p $(GEMINI_CERTIFICATES_DIR) sudo mkdir -p $(GEMINI_CERTIFICATES_DIR)
$(let gemini_user,$(shell whoami),sudo chown -R $(gemini_user):$(gemini_user) $(GEMINI_CERTIFICATES_DIR))
$(GEMINI_COMITIUM_DATA_DIR)/%: comitium-data/% $(GEMINI_COMITIUM_DATA_DIR) $(GEMINI_COMITIUM_DATA_DIR)/%: comitium-data/% $(GEMINI_COMITIUM_DATA_DIR)
sudo cp $< $@ sudo cp $< $@
$(let gemini_user,$(shell whoami),sudo chown $(gemini_user):$(gemini_user) $@)
$(GEMINI_COMITIUM_DATA_DIR): $(GEMINI_COMITIUM_DATA_DIR):
sudo mkdir -p $(GEMINI_COMITIUM_DATA_DIR) sudo mkdir -p $(GEMINI_COMITIUM_DATA_DIR)
+5 -5
View File
@@ -40,12 +40,12 @@ default_layout_file = $(if \
layout_file = $(if $(layout),share/layouts/$(layout).layout.upp$(ext),$(default_layout_file)) layout_file = $(if $(layout),share/layouts/$(layout).layout.upp$(ext),$(default_layout_file))
define out_rule = define out_rule =
out/%.$(ext): src/%$(if $(layout),.$(layout)).upp$(ext) $(layout_file) $(component_files) out/%.$(ext): src/%$(if $(layout),.$(layout)).upp$(ext) $(layout_file) $(component_files) bin/pp
./bin/mkws https://joeac.net "$$$$(realpath $$<)" ./bin/mkws https://joeac.net "$$$$(realpath $$<)"
endef endef
define blog_rss_feed_rule = define blog_rss_feed_rule =
out/$(blog)/rss.xml: src/$(blog)/rss.uppxml $(blog_src) $(wildcard bin/*) out/$(blog)/rss.xml: src/$(blog)/rss.uppxml $(blog_src) $(wildcard bin/*) bin/pp
./bin/mkws https://joeac.net "$$(realpath src/$(blog)/rss.uppxml)" ./bin/mkws https://joeac.net "$$(realpath src/$(blog)/rss.uppxml)"
endef endef
@@ -64,7 +64,7 @@ $(blog_post_target): $(blog_post_src) $(let ext,html,$(layout_file) $(component_
endef endef
define blog_index_rule = define blog_index_rule =
out/$(blog).html: src/$(blog).upphtml $(blog_src) $(wildcard bin/*) out/$(blog).html: src/$(blog).upphtml $(blog_src) $(wildcard bin/*) bin/pp
./bin/mkws https://joeac.net "$$(realpath src/$(blog).upphtml)" ./bin/mkws https://joeac.net "$$(realpath src/$(blog).upphtml)"
endef endef
@@ -106,10 +106,10 @@ share/man/man1/pp.1:
cp pp/pp.1 share/man/man1/pp.1 cp pp/pp.1 share/man/man1/pp.1
.PHONY: out .PHONY: out
out: bin/pp $(out_deps) out: $(out_deps)
bin/pp: bin/pp:
cd pp && $(MAKE) && chmod +x pp && cp pp ../bin/pp $(MAKE) --directory=pp && chmod +x pp/pp && cp pp/pp bin/pp
$(foreach ext,$(sort $(out_deps_ext)),\ $(foreach ext,$(sort $(out_deps_ext)),\
$(eval $(out_rule))) $(eval $(out_rule)))
+97 -21
View File
@@ -1,37 +1,113 @@
#!/bin/sh #!/bin/sh
set -e get_var_value()
{
expr "$(env | grep "^${1}=")" : "${1}=\(.*\)\$"
}
doas adduser -h /home/joeac.net joeac.net if [ -z "$(which podman 2>/dev/null)" ]
cd /home/joeac.net
sudo -u joeac.net git clone https://git.joeac.net/joeac.net.git joeac.net
sudo ln -s /home/joeac.net/joeac.net /usr/local/lib/joeac.net
cd joeac.net
if [ -z "${DIGITALOCEAN_TOKEN}" ]
then then
read -sp "DIGITALOCEAN_TOKEN: " DIGITALOCEAN_TOKEN sudo apk add podman
fi
if [ -z "$(which podman-compose 2>/dev/null)" ]
then
sudo apk add podman-compose
fi
if [ -z "$(which yq 2>/dev/null)" ]
then
YQ_PLATFORM="linux_$(expr "$(arch)" : "armv7" && echo arm || expr "$(arch)" : "x86_64" && echo amd64 || arch)"
sudo wget -O /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${YQ_PLATFORM}
sudo chmod +x /usr/local/bin/yq
fi
if [ -z "$(which envsubst 2>/dev/null)" ]
then
if [ "$(arch)" = "x86_64" ] || [ "$(arch)" = "arm64" ]
then
ENVSUBST_VERSION=1.4.3
sudo wget -O /usr/local/bin/envsubst https://github.com/a8m/envsubst/releases/download/v${ENVSUBST_VERSION}/envsubst-Linux-$(arch)
sudo chmod +x /usr/local/bin/envsubst
else
sudo apk add go
go install github.com/a8m/envsubst/cmd/envsubst@latest
fi
fi
if [ -z "$(which bash 2>/dev/null)" ]
then
sudo apk add bash
fi
if [ -z "$(grep "\bjoeac.net\b" /etc/group)" ]
then
sudo adduser -D -h /home/joeac.net joeac.net
sudo adduser joeac.net joeac.net
fi
if ! ( expr "$(groups joeac.net)" wheel )
then
sudo adduser joeac.net wheel
fi
su -l joeac.net
if ! [ $(whoami) = "joeac.net" ]
then
echo "Could not log in to user: joeac.net. Log in manually and re-run this script as joeac.net."
exit 1
fi
if ! [ -d /home/joeac.net/joeac.net/.git ]
then
git clone https://git.joeac.net/joeac/joeac.net.git /home/joeac.net/joeac.net
fi
sudo chown joeac.net:joeac.net /home/joeac.net/joeac.net
sudo chmod 770 /home/joeac.netjoeac.net
if ! [ -f DIGITALOCEAN_TOKEN ]
then
if [ -z "${DIGITALOCEAN_TOKEN}" ]
then
read -sp "DIGITALOCEAN_TOKEN: " DIGITALOCEAN_TOKEN
fi
echo ${DIGITALOCEAN_TOKEN} > /home/joeac.net/joeac.net/DIGITALOCEAN_TOKEN
fi
if ! ( podman secret exists remote_smtp_password )
then
if [ -z "${REMOTE_SMTP_PASSWORD}" ]
then
read -sp "REMOTE_SMTP_PASSWORD: " REMOTE_SMTP_PASSWORD
fi
echo "${REMOTE_SMTP_PASSWORD}" | podman secret create remote_smtp_password -
unset REMOTE_SMTP_PASSWORD
fi fi
echo ${DIGITALOCEAN_TOKEN} > DIGITALOCEAN_TOKEN
while read line while read line
do do
if expr "${line}" : "^[[:alnum:]_]\+=" 1>/dev/null if expr "${line}" : "[[:alnum:]_]\+=" 1>/dev/null
then then
var_name="$(expr "${line}" "^\([[:alnum:]_]\+\)=")" var_name="$(expr "${line}" : "\([[:alnum:]_]\+\)=")"
if [ -z "${!var_name}" ]
if [ -n "$(grep "^${var_name}=" /home/joeac.net/joeac.net/.env)" ]
then then
default_value="$(expr "${line}" "^[[:alnum:]_]\+=\(.*\)\$")" continue
fi
if [ -z "$(get_var_value ${var_name})" ]
then
default_value="$(expr "${line}" : "[[:alnum:]_]\+=\(.*\)\$")"
read -sp "${var_name}: " ${var_name} read -sp "${var_name}: " ${var_name}
if [ -z "${!var_name}" ] if [ -z "$(get_var_value ${var_name})" ]
then then
eval ${var_name}="${default_value}" eval ${var_name}="${default_value}"
fi fi
fi fi
echo "${var_name}=${!var_name}" >> .env
fi
done <example.env
sudo -u joeac.net make echo "${var_name}=$(get_var_value ${var_name})" >> /home/joeac.net/joeac.net/.env
sudo -u joeac.net make install fi
done </home/joeac.net/joeac.net/example.env
make --directory=/home/joeac.net/joeac.net
make --directory=/home/joeac.net/joeac.net install
-13
View File
@@ -1,16 +1,3 @@
CPU_ARCH := $(if $(shell which arch 2>/dev/null),\
$(shell arch),\
$(shell lscpu | grep ^Architecture: | sed "s/^Architecture:[[:space:]]*\([[:alnum:][:punct:]]\+\).*/\1/"))
IMAGE_PREFIX := $(if $(filter armv7%,$(CPU_ARCH)),armv7/)
COMPOSE_CMD := \
IMAGE_PREFIX="$(IMAGE_PREFIX)" \
GEMINI_CERTIFICATES_DIR="$(GEMINI_CERTIFICATES_DIR)" \
GEMINI_COMITIUM_DATA_DIR="$(GEMINI_COMITIUM_DATA_DIR)" \
ETHERPAD_DATA_DIR="$(ETHERPAD_DATA_DIR)" \
VAULTWARDEN_DATA_DIR="$(VAULTWARDEN_DATA_DIR)" \
LOCAL_SMTP_PORT=$(PORT_smtp) \
$(foreach module,$(ALL_MODULES),$(call capitalise,$(module))_PORT=$(PORT_$(module))) \
podman-compose
REGISTRY_DOMAIN := git.joeac.net REGISTRY_DOMAIN := git.joeac.net
REGISTRY_USER := joeac REGISTRY_USER := joeac
+7 -18
View File
@@ -5,7 +5,7 @@ dyndns_crontabs_to_remove = $(dyndns_subdomains_to_remove:%=/etc/periodic/daily/
define install_dyndns_module_rule = define install_dyndns_module_rule =
.PHONY: install_dyndns_$(module) .PHONY: install_dyndns_$(module)
install_dyndns_module_$(module): $(if $(SUBDOMAIN_$(module)),/etc/periodic/daily/dyndns-$(SUBDOMAIN_$(module)).joeac.net install_dyndns) install_dyndns_module_$(module): $(if $(SUBDOMAIN_$(module)),/etc/periodic/daily/dyndns-$(SUBDOMAIN_$(module)).joeac.net)
endef endef
define reinstall_dyndns_module_rule = define reinstall_dyndns_module_rule =
@@ -29,10 +29,10 @@ $(foreach module,$(ALL_MODULES), $(eval $(uninstall_dyndns_module_rule)))
remove_/etc/periodic/daily/dyndns-%.joeac.net: remove_/etc/periodic/daily/dyndns-%.joeac.net:
rm -f $(@:remove_%=%) rm -f $(@:remove_%=%)
/etc/periodic/daily/dyndns-%joeac.net: /usr/local/bin/dyndns.sh ~/.config/dyndns/DIGITALOCEAN_TOKEN /etc/periodic/daily/dyndns-%joeac.net: ~/digitalocean_dyndns/dyndns.sh ~/.config/dyndns/DIGITALOCEAN_TOKEN
echo "#!/bin/sh" > crontab.tmp echo "#!/bin/sh" > crontab.tmp
echo " /usr/local/bin/dyndns.sh 4 $(*F)joeac.net" >> crontab.tmp echo " $(shell realpath ~)/digitalocean_dyndns/dyndns.sh 4 $(*F)joeac.net" >> crontab.tmp
echo "CONN_DEVICE_NAME=eth0 /usr/local/bin/dyndns.sh 6 $(*F)joeac.net" >> crontab.tmp echo "CONN_DEVICE_NAME=eth0 $(shell realpath ~)/digitalocean_dyndns/dyndns.sh 6 $(*F)joeac.net" >> crontab.tmp
sudo mv crontab.tmp $@ sudo mv crontab.tmp $@
sudo chmod +x $@ sudo chmod +x $@
@@ -42,23 +42,12 @@ reinstall_dyndns: $(addprefix remove_,$(dyndns_crontabs_to_remove))
.PHONY: uninstall_dyndns .PHONY: uninstall_dyndns
uninstall_dyndns: $(foreach module,$(ALL_MODULES),$(uninstall_dyndns_$(module))) uninstall_dyndns: $(foreach module,$(ALL_MODULES),$(uninstall_dyndns_$(module)))
sudo rm -rf \ sudo rm -rf \
/usr/local/bin/dyndns.sh \ ~/digitalocean_dyndns/ \
/usr/local/bin/get_ip_addr.sh \
/usr/local/lib/digitalocean_dyndns/ \
~/.config/dyndns \ ~/.config/dyndns \
~/.cache/dyndns ~/.cache/dyndns
/usr/local/bin/dyndns.sh: /usr/local/lib/digitalocean_dyndns/dyndns.sh /usr/local/bin/get_ip_addr.sh ~/digitalocean_dyndns/%:
sudo rm -f /usr/local/bin/dyndns.sh git clone https://git.joeac.net/joeac/digitalocean_dyndns.git ~/digitalocean_dyndns
sudo cp /usr/local/lib/digitalocean_dyndns/dyndns.sh /usr/local/bin/dyndns.sh
/usr/local/bin/get_ip_addr.sh: /usr/local/lib/digitalocean_dyndns/get_ip_addr.sh
sudo rm -f /usr/local/bin/get_ip_addr.sh
sudo cp /usr/local/lib/digitalocean_dyndns/get_ip_addr.sh /usr/local/bin/get_ip_addr.sh
/usr/local/lib/digitalocean_dyndns/%:
cd /usr/local/lib \
&& sudo git clone https://git.joeac.net/joeac/digitalocean_dyndns.git
~/.config/dyndns/DIGITALOCEAN_TOKEN: DIGITALOCEAN_TOKEN ~/.config/dyndns/DIGITALOCEAN_TOKEN: DIGITALOCEAN_TOKEN
mkdir -p ~/.config/dyndns/ mkdir -p ~/.config/dyndns/
+4 -2
View File
@@ -6,6 +6,7 @@ nginx_module_config_template = \
$(if $(PORT_$(module)),nginx/http.d/reverse_proxy.conf.template) \ $(if $(PORT_$(module)),nginx/http.d/reverse_proxy.conf.template) \
$(if $(PUBLIC_ROOT_DIR_$(module)),nginx/http.d/static.conf.template) $(if $(PUBLIC_ROOT_DIR_$(module)),nginx/http.d/static.conf.template)
nginx_module_config_template_args = \ nginx_module_config_template_args = \
CERTNAME=$(SUBDOMAIN_$(module)).joeac.net \
DOMAIN=$(if $(filter-out @,$(SUBDOMAIN_$(module))),$(SUBDOMAIN_$(module)).)joeac.net \ DOMAIN=$(if $(filter-out @,$(SUBDOMAIN_$(module))),$(SUBDOMAIN_$(module)).)joeac.net \
$(if $(PORT_$(module)),PORT=$(PORT_$(module)) HOST=$(HOST_$(module))) \ $(if $(PORT_$(module)),PORT=$(PORT_$(module)) HOST=$(HOST_$(module))) \
$(if $(PUBLIC_ROOT_DIR_$(module)),ROOT="$(PUBLIC_ROOT_DIR_$(module))") $(if $(PUBLIC_ROOT_DIR_$(module)),ROOT="$(PUBLIC_ROOT_DIR_$(module))")
@@ -28,12 +29,13 @@ endef
define remove_nginx_site_rule = define remove_nginx_site_rule =
remove_$(site): remove_$(site):
rm -f $(site) sudo rm -f $(site)
endef endef
define nginx_module_config_rule = define nginx_module_config_rule =
/etc/nginx/http.d/$(SUBDOMAIN_$(module)).joeac.net.conf: $(nginx_module_config_template) /etc/nginx/http.d /etc/nginx/nginx.conf /etc/nginx/http.d/$(SUBDOMAIN_$(module)).joeac.net.conf: $(nginx_module_config_template) /etc/nginx/http.d /etc/nginx/nginx.conf
sudo $(nginx_module_config_template_args) envsubst -i $$< -o $$@ $(nginx_module_config_template_args) envsubst -i $$< -o $$(notdir $$@).tmp
sudo cp $$(notdir $$@).tmp $$@
sudo rc-service nginx restart sudo rc-service nginx restart
endef endef
+11 -9
View File
@@ -6,7 +6,7 @@ define install_openrc_module_rule =
install_openrc_$(module): $(if $(is_openrc_module),$(openrc_module_target) openrc_add_$(module) openrc_start_$(module)) install_openrc_$(module): $(if $(is_openrc_module),$(openrc_module_target) openrc_add_$(module) openrc_start_$(module))
~/.config/rc/init.d/joeac.net.$(module): ~/.config/rc/init.d/joeac.net ~/.config/rc/runlevels/default ~/.config/rc/init.d/joeac.net.$(module): ~/.config/rc/init.d/joeac.net ~/.config/rc/runlevels/default
rm -f ~/.config/rc/init.d/joeac.net rm -f ~/.config/rc/init.d/joeac.net.$(module)
ln -s $(shell realpath ~)/.config/rc/init.d/joeac.net ~/.config/rc/init.d/joeac.net.$(module) ln -s $(shell realpath ~)/.config/rc/init.d/joeac.net ~/.config/rc/init.d/joeac.net.$(module)
endef endef
@@ -43,17 +43,18 @@ openrc_restart_$(module):
rc-service -U joeac.net.$(module) restart rc-service -U joeac.net.$(module) restart
endef endef
$(foreach module,$(MODULES),$(eval $(install_openrc_module_rule))) $(foreach module,$(ALL_MODULES),$(eval $(install_openrc_module_rule)))
$(foreach module,$(MODULES),$(eval $(reinstall_openrc_module_rule))) $(foreach module,$(ALL_MODULES),$(eval $(reinstall_openrc_module_rule)))
$(foreach module,$(MODULES),$(eval $(uninstall_openrc_module_rule))) $(foreach module,$(ALL_MODULES),$(eval $(uninstall_openrc_module_rule)))
$(foreach module,$(MODULES),$(eval $(openrc_add_rule))) $(foreach module,$(ALL_MODULES),$(eval $(openrc_add_rule)))
$(foreach module,$(MODULES),$(eval $(openrc_start_rule))) $(foreach module,$(ALL_MODULES),$(eval $(openrc_start_rule)))
$(foreach module,$(MODULES),$(eval $(openrc_restart_rule))) $(foreach module,$(MODULES),$(eval $(openrc_restart_rule)))
~/.config/rc/init.d/joeac.net: openrc/init.d/joeac.net ~/.config/rc/init.d ~/.config/rc/runlevels/default /etc/init.d/user.$(USER) /etc/conf.d/user.$(USER) ~/.config/rc/init.d/joeac.net: openrc/init.d/joeac.net.template ~/.config/rc/init.d ~/.config/rc/runlevels/default /etc/init.d/user.$(USER) /etc/conf.d/user.$(USER)
rm -f ~/.config/rc/init.d/joeac.net; \ rm -f ~/.config/rc/init.d/joeac.net; \
mkdir -p ~/.config/rc/init.d; \ mkdir -p ~/.config/rc/init.d; \
cp openrc/init.d/joeac.net ~/.config/rc/init.d/joeac.net COMPOSECMD="$(COMPOSE_CMD)" envsubst -i openrc/init.d/joeac.net.template -o ~/.config/rc/init.d/joeac.net
chmod +x ~/.config/rc/init.d/joeac.net
~/.config/rc/init.d: ~/.config/rc/init.d:
mkdir -p ~/.config/rc/init.d mkdir -p ~/.config/rc/init.d
@@ -65,7 +66,8 @@ $(foreach module,$(MODULES),$(eval $(openrc_restart_rule)))
sudo ln -s /etc/init.d/user /etc/init.d/user.$(USER) sudo ln -s /etc/init.d/user /etc/init.d/user.$(USER)
/etc/conf.d/user.$(USER): openrc/conf.d/user.template /etc/conf.d/user.$(USER): openrc/conf.d/user.template
sudo USER=$(USER) envsubst openrc/conf.d/user.template /etc/conf.d/user.$(USER) USER=$(USER) envsubst -i openrc/conf.d/user.template -o openrc/conf.d/user.$(USER)
sudo mv openrc/conf.d/user.$(USER) /etc/conf.d/user.$(USER)
sudo rc-update add user.$(USER) default sudo rc-update add user.$(USER) default
.PHONY: uninstall_joeac.net_service .PHONY: uninstall_joeac.net_service
+88
View File
@@ -0,0 +1,88 @@
installed_tls_crontabs = $(wildcard /etc/periodic/daily/tls-*.joeac.net)
installed_tls_crontab_subdomains = $(installed_tls_crontabs:/etc/periodic/daily/tls-%.joeac.net=%)
tls_crontab_subdomains_to_remove = $(filter-out $(SUBDOMAINS),$(installed_tls_crontab_subdomains))
tls_crontabs_to_remove = $(tls_crontab_subdomains_to_remove:%=/etc/periodic/daily/tls-%.joeac.net)
installed_tls_certs = $(wildcard /etc/letsencrypt/live/*.joeac.net)
installed_tls_cert_subdomains = $(installed_tls_certs:/etc/letsencrypt/live/%.joeac.net=%)
tls_cert_subdomains_to_delete = $(filter-out $(SUBDOMAINS),$(installed_tls_cert_subdomains))
tls_crontab = /etc/periodic/daily/tls-$(subdomain).joeac.net
tls_cert = /etc/letsencrypt/live/$(subdomain).joeac.net/fullchain.pem
define install_tls_subdomain_rule =
.PHONY: install_tls_$(subdomain)
install_tls_$(subdomain): $(tls_crontab) $(tls_cert)
endef
define reinstall_tls_subdomain_rule =
.PHONY: reinstall_tls_$(subdomain)
reinstall_tls_$(subdomain): $(tls_crontab) renew_$(tls_cert)
endef
define uninstall_tls_subdomain_rule =
.PHONY: uninstall_tls_$(subdomain)
uninstall_tls_$(subdomain): delete_cert_$(subdomain).joeac.net
$(if $(shell [ -f $(tls_crontab) ] && echo 1),\
sudo rm -f $(tls_crontab)
)
endef
define obtain_or_renew_cert_cmd =
sudo certbot certonly \
--nginx \
--cert-name $(subdomain).joeac.net \
--domain $(subst @.,,$(subdomain).)joeac.net \
&& sudo chown -R joeac.net:joeac.net $(dir $(tls_cert))
endef
is_cert_expired = $(shell sudo certbot certificates --cert-name $(subdomain).joeac.net \
| grep "Expiry Date" | grep -E "(EXPIRED|REVOKED)")
define cert_rule =
$(tls_cert):
$(obtain_or_renew_cert_cmd)
.PHONY: renew_$(tls_cert)
renew_$(tls_cert):
$$(if $$(is_cert_expired),$(obtain_or_renew_cert_cmd))
endef
$(foreach subdomain,$(ALL_SUBDOMAINS), $(eval $(install_tls_subdomain_rule)))
$(foreach subdomain,$(ALL_SUBDOMAINS), $(eval $(reinstall_tls_subdomain_rule)))
$(foreach subdomain,$(ALL_SUBDOMAINS), $(eval $(uninstall_tls_subdomain_rule)))
$(foreach subdomain,$(ALL_SUBDOMAINS), $(eval $(cert_rule)))
.PHONY: remove_/etc/periodic/daily/tls-%.joeac.net
remove_/etc/periodic/daily/tls-%.joeac.net:
rm -f $(@:remove_%=%)
.PHONY: delete_cert_%
delete_cert_%:
sudo certbot delete --cert-name $(@:delete_cert_%=%).joeac.net --non-interactive
/etc/periodic/daily/tls-%joeac.net:
echo "#!/bin/sh" > crontab.tmp
echo "$(obtain_or_renew_cert_cmd)" >> crontab.tmp
sudo mv crontab.tmp $@
sudo chmod +x $@
certs_to_renew = $(foreach subdomain,$(filter $(SUBDOMAINS),$(installed_tls_cert_subdomains)),$(tls_cert))
tls_crontabs_to_install = $(foreach subdomain,$(SUBDOMAINS),$(tls_crontab))
tls_certs_to_install = $(foreach subdomain,$(SUBDOMAINS),$(tls_cert))
.PHONY: install_tls
install_tls: $(tls_crontabs_to_install) $(tls_certs_to_install) $(addprefix remove_,$(tls_crontabs_to_remove)) $(addprefix delete_cert_,$(tls_cert_subdomains_to_delete)) $(addprefix renew_,$(certs_to_renew))
.PHONY: reinstall_tls
reinstall_tls: install_tls
.PHONY: uninstall_tls
uninstall_tls: $(foreach subdomain,$(ALL_SUBDOMAINS),$(uninstall_tls_$(subdomain)))
.PHONY: install_certbot
install_certbot: /usr/bin/certbot /usr/bin/python /usr/lib/$(shell ls /usr/bin | grep python[0-9]\\.)/certbot_nginx
/usr/bin/certbot /usr/bin/python:
sudo apk add certbot
/usr/lib/python%/certbot_nginx:
sudo apk add certbot-nginx
+35 -6
View File
@@ -3,10 +3,12 @@ capitalise = $(shell echo "$(1)" | tr '[:lower:]' '[:upper:]')
USER := $(shell whoami) USER := $(shell whoami)
HOSTNAME := $(shell cat /etc/hostname) HOSTNAME := $(shell cat /etc/hostname)
HOSTNAMES := pi-broughton blade-canongate HOSTNAMES := pi-broughton blade-canongate
MASTER_NODE := pi-broughton IP_ADDR_pi-broughton := 192.168.178.54
IP_ADDR_blade-canongate := 192.168.178.75
MASTER_NODE := blade-canongate
IS_MASTER_NODE := $(filter $(MASTER_NODE),$(HOSTNAME)) IS_MASTER_NODE := $(filter $(MASTER_NODE),$(HOSTNAME))
MODULES_pi-broughton := http gemini smtp vaultwarden ln MODULES_pi-broughton := http smtp vaultwarden ln
MODULES_blade-canongate := etherpad MODULES_blade-canongate := etherpad gemini mox mox_clientsettings mox_autoconfig mox_mta_sts
ALL_NGINX_MODULES := http vaultwarden ln etherpad ALL_NGINX_MODULES := http vaultwarden ln etherpad
NGINX_MODULES := $(if $(IS_MASTER_NODE),$(ALL_NGINX_MODULES)) NGINX_MODULES := $(if $(IS_MASTER_NODE),$(ALL_NGINX_MODULES))
MODULES := $(MODULES_$(HOSTNAME)) MODULES := $(MODULES_$(HOSTNAME))
@@ -20,10 +22,17 @@ SUBDOMAIN_http := @
SUBDOMAIN_vaultwarden := pwd SUBDOMAIN_vaultwarden := pwd
SUBDOMAIN_etherpad := docs SUBDOMAIN_etherpad := docs
SUBDOMAIN_ln := ln SUBDOMAIN_ln := ln
SUBDOMAIN_mox := mail
SUBDOMAIN_mox_autoconfig := autoconfig.mail
SUBDOMAIN_mox_clientsettings := clientsettings.mail
SUBDOMAIN_mox_mta_sts := mta-sts.mail
PORT_etherpad := 9001 PORT_etherpad := 9001
PORT_http := 8080 PORT_http := 8080
PORT_gemini := 1965 PORT_gemini := 1965
PORT_mox := 81
PORT_mox_autoconfig := $(PORT_mox)
PORT_mox_mta_sts := $(PORT_mox)
PORT_smtp := 2500 PORT_smtp := 2500
PORT_vaultwarden := 9000 PORT_vaultwarden := 9000
@@ -34,15 +43,19 @@ export GEMINI_CERTIFICATES_DIR := /var/joeac.net-gemini/certificates
export GEMINI_COMITIUM_DATA_DIR := /var/joeac.net-gemini/comitium-data export GEMINI_COMITIUM_DATA_DIR := /var/joeac.net-gemini/comitium-data
export VAULTWARDEN_DATA_DIR := /var/vaultwarden/data export VAULTWARDEN_DATA_DIR := /var/vaultwarden/data
ALPINE_VERSION := 3.23
ETHERPAD_VERSION := 3.3.2
$(foreach module,$(ALL_MODULES),$(if $(PORT_$(module)),$(eval \ $(foreach module,$(ALL_MODULES),$(if $(PORT_$(module)),$(eval \
export $(call capitalise,$(module))_PORT := $(PORT_$(module))))) export $(call capitalise,$(module))_PORT := $(PORT_$(module)))))
$(foreach hostname,$(HOSTNAMES),$(foreach module,$(MODULES_$(hostname)),$(eval \ $(foreach hostname,$(HOSTNAMES),$(foreach module,$(MODULES_$(hostname)),$(eval \
export HOST_$(module) := $(hostname:$(HOSTNAME)=localhost)))) export HOST_$(module) := $(if $(filter $(HOSTNAME),$(hostname)),127.0.0.1,$(IP_ADDR_$(hostname))))))
SUBDOMAINS := $(foreach module,$(MODULES),$(SUBDOMAIN_$(module))) ALL_SUBDOMAINS := $(foreach module,$(ALL_MODULES),$(SUBDOMAIN_$(module)))
SUBDOMAINS := $(if $(IS_MASTER_NODE),$(ALL_SUBDOMAINS))
NGINX_SUBDOMAINS := $(foreach module,$(NGINX_MODULES),$(SUBDOMAIN_$(module))) NGINX_SUBDOMAINS := $(foreach module,$(NGINX_MODULES),$(SUBDOMAIN_$(module)))
ENV_RULES := $(foreach module,$(MODULES),$(module)/.env) ENV_RULES := $(foreach module,$(MODULES),$(if $(shell test -d $(module) && echo 1),$(module)/.env))
MAKE_RULES := $(foreach module,$(MAKE_MODULES),make_$(module)) MAKE_RULES := $(foreach module,$(MAKE_MODULES),make_$(module))
BUILD_RULES := $(foreach module,$(filter $(COMPOSE_SERVICES),$(MODULES)),build_$(module)) BUILD_RULES := $(foreach module,$(filter $(COMPOSE_SERVICES),$(MODULES)),build_$(module))
PUSH_RULES := $(foreach module,$(filter $(COMPOSE_SERVICES),$(MODULES)),push_$(module)) PUSH_RULES := $(foreach module,$(filter $(COMPOSE_SERVICES),$(MODULES)),push_$(module))
@@ -50,6 +63,22 @@ INSTALL_RULES := $(foreach module,$(MODULES),install_$(module))
REINSTALL_RULES := $(foreach module,$(MODULES),reinstall_$(module)) REINSTALL_RULES := $(foreach module,$(MODULES),reinstall_$(module))
UNINSTALL_RULES := $(foreach module,$(MODULES),uninstall_$(module)) UNINSTALL_RULES := $(foreach module,$(MODULES),uninstall_$(module))
CPU_ARCH := $(if $(shell which arch 2>/dev/null),\
$(shell arch),\
$(shell lscpu | grep ^Architecture: | sed "s/^Architecture:[[:space:]]*\([[:alnum:][:punct:]]\+\).*/\1/"))
IMAGE_PREFIX := $(if $(filter armv7%,$(CPU_ARCH)),armv7/)
COMPOSE_CMD := \
ALPINE_VERSION="$(ALPINE_VERSION)" \
IMAGE_PREFIX="$(IMAGE_PREFIX)" \
GEMINI_CERTIFICATES_DIR="$(GEMINI_CERTIFICATES_DIR)" \
GEMINI_COMITIUM_DATA_DIR="$(GEMINI_COMITIUM_DATA_DIR)" \
ETHERPAD_DATA_DIR="$(ETHERPAD_DATA_DIR)" \
ETHERPAD_VERSION="$(ETHERPAD_VERSION)" \
VAULTWARDEN_DATA_DIR="$(VAULTWARDEN_DATA_DIR)" \
LOCAL_SMTP_PORT=$(PORT_smtp) \
$(foreach module,$(ALL_MODULES),$(call capitalise,$(module))_PORT=$(PORT_$(module))) \
podman-compose
$(foreach module,$(ALL_NGINX_MODULES), \ $(foreach module,$(ALL_NGINX_MODULES), \
$(if $(SUBDOMAIN_$(module)),, \ $(if $(SUBDOMAIN_$(module)),, \
$(error $(module) is declared as an nginx module, but SUBDOMAIN_$(module) is not set))) $(error $(module) is declared as an nginx module, but SUBDOMAIN_$(module) is not set)))
+2
View File
@@ -0,0 +1,2 @@
config/dkim
config/adminpasswd
+6
View File
@@ -0,0 +1,6 @@
# mox
There are three secrets required for mox. One is the admin password, which
should be stored in config/adminpasswd. The other two are DKIM private keys,
which should be stored in the config/dkim directory. The public parts of these
keys should be exposed in DNS TXT records.
+52
View File
@@ -0,0 +1,52 @@
Domains:
mail.joeac.net:
ClientSettingsDomain: clientsettings.mail.joeac.net
LocalpartCatchallSeparator: +
DKIM:
Selectors:
2026a:
Expiration: 72h
PrivateKeyFile: dkim/2026a._domainkey.mail.joeac.net.20260705T163220.rsa2048.privatekey.pkcs8.pem
2026b:
Expiration: 72h
PrivateKeyFile: dkim/2026b._domainkey.mail.joeac.net.20260705T163220.rsa2048.privatekey.pkcs8.pem
Sign:
- 2026a
DMARC:
Localpart: dmarcreports
Account: me
Mailbox: DMARC
MTASTS:
PolicyID: 20260705T153220
Mode: enforce
MaxAge: 24h0m0s
MX:
- mail.joeac.net
TLSRPT:
Localpart: tlsreports
Account: me
Mailbox: TLSRPT
Accounts:
me:
Domain: mail.joeac.net
Destinations:
me@mail.joeac.net: nil
SubjectPass:
Period: 12h0m0s
RejectsMailbox: Rejects
AutomaticJunkFlags:
Enabled: true
JunkMailboxRegexp: ^(junk|spam)
NeutralMailboxRegexp: ^(inbox|neutral|postmaster|dmarc|tlsrpt|rejects)
JunkFilter:
Threshold: 0.950000
Params:
Onegrams: true
MaxPower: 0.010000
TopWords: 10
IgnoreWords: 0.100000
RareWords: 2
NoCustomPassword: true
MonitorDNSBLs:
- sbl.spamhaus.org
- bl.spamcop.net
+74
View File
@@ -0,0 +1,74 @@
DataDir: ../data
LogLevel: debug
User: mox
Hostname: mail.joeac.net
AdminPasswordFile: adminpasswd
Listeners:
internal:
IPs:
- 127.0.0.1
- ::1
Hostname: localhost
AccountHTTP:
Enabled: true
Port: 1080
Forwarded: true
AdminHTTP:
Enabled: true
Port: 1080
Forwarded: true
WebmailHTTP:
Enabled: true
Port: 1080
Forwarded: true
WebAPIHTTP:
Enabled: true
Port: 1080
Forwarded: true
MetricsHTTP:
Enabled: true
AutoconfigHTTPS:
Enabled: true
Port: 81
NonTLS: true
MTASTSHTTPS:
Enabled: true
Port: 81
NonTLS: true
WebserverHTTP:
Enabled: true
Port: 81
public:
IPs:
- 192.168.178.75
- fdc9:6aec:7a18:0:2e0:4cff:fe61:9b17
NATIPs:
- 217.155.190.42
- fdc9:6aec:7a18:0:2e0:4cff:fe61:9b17
TLS:
KeyCerts:
-
CertFile: /etc/letsencrypt/live/mail.joeac.net/fullchain.pem
KeyFile: /etc/letsencrypt/live/mail.joeac.net/privkey.pem
-
CertFile: /etc/letsencrypt/live/mta-sts.mail.joeac.net/fullchain.pem
KeyFile: /etc/letsencrypt/live/mta-sts.mail.joeac.net/privkey.pem
-
CertFile: /etc/letsencrypt/live/autoconfig.mail.joeac.net/fullchain.pem
KeyFile: /etc/letsencrypt/live/autoconfig.mail.joeac.net/privkey.pem
-
CertFile: /etc/letsencrypt/live/clientsettings.mail.joeac.net/fullchain.pem
KeyFile: /etc/letsencrypt/live/clientsettings.mail.joeac.net/privkey.pem
SMTP:
Enabled: true
Submissions:
Enabled: true
IMAPS:
Enabled: true
Postmaster:
Account: me
Mailbox: Postmaster
HostTLSRPT:
Account: me
Mailbox: TLSRPT
Localpart: tlsreports
+8
View File
@@ -0,0 +1,8 @@
server:
auto-trust-anchor-file: /var/lib/unbound/root.key
qname-minimisation: yes
interface: 0.0.0.0
access-control: 192.168.0.0/16 allow
remote-control:
control-enable: yes
+60
View File
@@ -0,0 +1,60 @@
.PHONY: install
install: install_unbound install_mox
.PHONY: reinstall
reinstall: install_unbound install_mox
.PHONY: install_unbound
install_unbound: /usr/sbin/unbound /etc/resolv.conf /var/lib/unbound/root.key install_unbound_anchor_crontab /etc/unbound/unbound.conf.d/dnssec.conf
/usr/sbin/unbound:
sudo apk add unbound
sudo rc-update add unbound default
sudo rc-service unbound start
/etc/resolv.conf: resolv.conf /etc/resolv.conf.joeac.net-backup
sudo cp resolv.conf /etc/resolv.conf
/etc/resolv.conf.joeac.net-backup:
sudo mv /etc/resolv.conf /etc/resolv.conf.joeac.net-backup
/var/lib/unbound/root.key:
sudo mkdir -p /var/lib/unbound && sudo unbound-anchor -a /var/lib/unbound/root.key
UNBOUND_ANCHOR_CRONTAB_ENTRY := @reboot unbound-anchor -a /var/lib/unbound/root.key # managed by joeac.net
IS_CRONTAB_UP_TO_DATE := $(sudo grep "$(UNBOUND_ANCHOR_CRONTAB_ENTRY)" /etc/crontabs/root)
.PHONY: install_unbound_anchor_crontab
install_unbound_anchor_crontab:
$(if $(IS_CRONTAB_UP_TO_DATE),,\
sudo crontab -l > crontab.tmp; \
sed -i "s/.*unbound-anchor.*# managed by joeac.net//" crontab.tmp; \
echo "$(UNBOUND_ANCHOR_CRONTAB_ENTRY)" >> crontab.tmp; \
sudo crontab crontab.tmp; \
rm crontab.tmp; \
)
/etc/unbound/unbound.conf.d/dnssec.conf: dnssec.conf
sudo mkdir -p $(dir $@) && sudo cp $< $@
DKIM_PRIVATE_KEY_A := ~/mox/config/dkim/2026a._domainkey.mail.joeac.net.20260705T163220.rsa2048.privatekey.pkcs8.pem
DKIM_PRIVATE_KEY_B := ~/mox/config/dkim/2026b._domainkey.mail.joeac.net.20260705T163220.rsa2048.privatekey.pkcs8.pem
DKIM_PRIVATE_KEYS := $(DKIM_PRIVATE_KEY_A) $(DKIM_PRIVATE_KEY_B)
MOX_TLS_CERTS := /etc/letsencrypt/live/mail.joeac.net/fullchain.pem /etc/letsencrypt/live/autoconfig.mail.joeac.net/fullchain.pem /etc/letsencrypt/live/clientsettings.mail.joeac.net/fullchain.pem /etc/letsencrypt/live/mta-sts.mail.joeac.net/fullchain.pem
.PHONY: install_mox
install_mox: /usr/local/bin/mox ~/mox/config/mox.conf ~/mox/config/domains.conf ~/mox/config/adminpasswd $(DKIM_PRIVATE_KEYS) $(MOX_TLS_CERTS)
MOX_PLATFORM := $(if $(filter armv7% arm32%,$(CPU_ARCH)),arm,amd64)
MOX_VERSION := 0.0.15
MOX_GO_VERSION := 1.26.4
MOX_CHECKSUM_amd64_v0.0.15_go1.26.4 := 09OE-1QkNVgmpoRj53mtX9gxoEmY
MOX_CHECKSUM_arm_v0.0.15_go1.26.4 := 038X9nQx6hhai60Fk1BhcP3r6Mew
MOX_CHECKSUM := $(MOX_CHECKSUM_$(MOX_PLATFORM)_v$(MOX_VERSION)_go$(MOX_GO_VERSION))
MOX_URL_BASE := https://beta.gobuilds.org/github.com/mjl-/mox
MOX_URL := $(MOX_URL_BASE)@v$(MOX_VERSION)/linux-$(MOX_PLATFORM)-go$(MOX_GO_VERSION)/$(MOX_CHECKSUM)
/usr/local/bin/mox:
wget -O- $(MOX_URL) | gzip -d > mox
chmod +x mox
sudo mv mox /usr/local/bin/mox
~/mox/config/%: config/%
mkdir -p $(dir $@) && cp $< $@
+1
View File
@@ -0,0 +1 @@
nameserver: 127.0.0.1
+4 -4
View File
@@ -2,12 +2,12 @@ server {
server_name ${DOMAIN}; server_name ${DOMAIN};
location / { location / {
root ${ROOT}; root ${ROOT};
try_files $uri $uri.html $uri/index.html =404; try_files $$uri $$uri.html $$uri/index.html =404;
error_page 404 /index.html; error_page 404 /index.html;
} }
listen 443 ssl; listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${CERTNAME}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${CERTNAME}/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf; include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
} }
@@ -18,5 +18,5 @@ server {
} # managed by Certbot } # managed by Certbot
server_name ln.joeac.net; server_name ln.joeac.net;
listen 80; listen 80;
return 404; # managed by Certbot return 404;
} }
-65
View File
@@ -1,65 +0,0 @@
#!/sbin/openrc-run
# credits:
# https://gist.github.com/itzwam/2069e935385193207f7e5bea7156e21d
# https://github.com/0x17de/dockerservice-openrc
: ${MODULENAME:=${RC_SVCNAME##*.}}
: ${SRCDIR:=/usr/local/lib/joeac.net}
DOCKER_COMPOSE_UP_ARGS=${DOCKER_COMPOSE_UP_ARGS-"--no-build --no-recreate --no-deps"}
[ -z "${MODULENAME}" ] && exit 1
: ${COMPOSEFILE:="${SRCDIR}/compose.yml"}
: ${MAKEFILE:="${SRCDIR}/Makefile"}
COMPOSECMD="/usr/bin/podman-compose"
export COMPOSE_HTTP_TIMEOUT=300
description="Manage dockerservices defined in ${COMPOSEFILE}"
extra_commands="configtest"
description_configtest="Check configuration via \"podman-compose -f ${COMPOSEFILE} config\""
configtest() {
if ! [ -f "${COMPOSEFILE}" ]; then
eerror "The docker-compose file ${COMPOSEFILE} does not exist!"
return 1
fi
if "${COMPOSECMD}" -f "${COMPOSEFILE}" config >&/dev/null; then
einfo "config: ok"
else
eerror "config: error"
return 1
fi
}
start() {
configtest || return 1
ebegin "Starting ${MODULENAME}"
"${COMPOSECMD}" -f "${COMPOSEFILE}" up -d ${DOCKER_COMPOSE_UP_ARGS} ${MODULENAME}
eend $?
}
stop() {
ebegin "Stopping ${MODULENAME}"
"${COMPOSECMD}" -f "${COMPOSEFILE}" down --timeout=5 ${MODULENAME}
eend $?
}
status() {
pods=0
started=0
while read pod; do
pod_service="$(podman inspect $pod | jq .[0].Config.Labels.[\"com.docker.compose.service\"])"
if ! [ "$pod_service" = "\"${MODULENAME}\"" ]; then
continue
fi
pods=$(($pods+1))
if podman top $pod &>/dev/null; then
einfo "status: [$pod] started"
exit 0
else
einfo "status: [$pod] stopped"
exit 3
fi
done < <("${COMPOSECMD}" -f "${COMPOSEFILE}" ps --quiet)
einfo "status: no container found for ${MODULENAME}"
exit 3
}
+65
View File
@@ -0,0 +1,65 @@
#!/sbin/openrc-run
# credits:
# https://gist.github.com/itzwam/2069e935385193207f7e5bea7156e21d
# https://github.com/0x17de/dockerservice-openrc
: $${HOME:=/home/joeac.net}
: $${MODULENAME:=$${RC_SVCNAME##*.}}
: $${SRCDIR:=$$HOME/joeac.net}
DOCKER_COMPOSE_UP_ARGS=$${DOCKER_COMPOSE_UP_ARGS-"--no-build --no-recreate --no-deps"}
[ -z "$${MODULENAME}" ] && exit 1
: $${COMPOSEFILE:="$${SRCDIR}/compose.yml"}
: $${MAKEFILE:="$${SRCDIR}/Makefile"}
export COMPOSE_HTTP_TIMEOUT=300
description="Manage dockerservices defined in $${COMPOSEFILE}"
extra_commands="configtest"
description_configtest="Check configuration via \"podman-compose -f $${COMPOSEFILE} config\""
configtest() {
if ! [ -f "$${COMPOSEFILE}" ]; then
eerror "The docker-compose file $${COMPOSEFILE} does not exist!"
return 1
fi
if ${COMPOSECMD} -f "$${COMPOSEFILE}" config >&/dev/null; then
einfo "config: ok"
else
eerror "config: error"
return 1
fi
}
start() {
configtest || return 1
ebegin "Starting $${MODULENAME}"
${COMPOSECMD} -f "$${COMPOSEFILE}" up -d $${DOCKER_COMPOSE_UP_ARGS} $${MODULENAME}
eend $$?
}
stop() {
ebegin "Stopping $${MODULENAME}"
${COMPOSECMD} -f "$${COMPOSEFILE}" down --timeout=5 $${MODULENAME}
eend $$?
}
status() {
pods=0
started=0
while read pod; do
pod_service="$$(podman inspect $$pod | jq .[0].Config.Labels.[\"com.docker.compose.service\"])"
if ! [ "$$pod_service" = "\"$${MODULENAME}\"" ]; then
continue
fi
pods=$$(($$pods+1))
if podman top $$pod &>/dev/null; then
einfo "status: [$$pod] started"
exit 0
else
einfo "status: [$$pod] stopped"
exit 3
fi
done < <(${COMPOSECMD} -f "$${COMPOSEFILE}" ps --quiet)
einfo "status: no container found for $${MODULENAME}"
exit 3
}
+5
View File
@@ -1,5 +1,10 @@
#!/bin/sh #!/bin/sh
if [ -z "${XDG_RUNTIME_DIR}" ]
then
export XDG_RUNTIME_DIR=/tmp/xdg/$(id -u joeac.net)-xdg-runtime-dir
fi
cd /home/joeac.net/joeac.net \ cd /home/joeac.net/joeac.net \
&& sudo -u joeac.net git pull \ && sudo -u joeac.net git pull \
&& sudo -u joeac.net make \ && sudo -u joeac.net make \
+1
View File
@@ -6,6 +6,7 @@ reinstall: $(VAULTWARDEN_DATA_DIR)
$(VAULTWARDEN_DATA_DIR): $(VAULTWARDEN_DATA_DIR):
sudo mkdir -p $(VAULTWARDEN_DATA_DIR) sudo mkdir -p $(VAULTWARDEN_DATA_DIR)
VAULTWARDEN_USER=$(whoami) && sudo chown $$VAULTWARDEN_USER:$$VAULTWARDEN_USER $(VAULTWARDEN_DATA_DIR)
.PHONY: uninstall .PHONY: uninstall
uninstall: uninstall: