Compare commits
258 Commits
e04d1e55a1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 87527646fa | |||
| 30af54b750 | |||
| ac0ebb5302 | |||
| 4bf24c2b18 | |||
| 20b396effd | |||
| b3677dad4c | |||
| b181f59f4c | |||
| 5d849384bc | |||
| 5e640711ce | |||
| 44e4605be8 | |||
| 60ba3328fa | |||
| 5a5301fefb | |||
| 4ee7c34161 | |||
| fe1d19a9c7 | |||
| 6d8541f052 | |||
| ba2359f8b9 | |||
| 9ef09754be | |||
| cbe223166e | |||
| fb2785f694 | |||
| f9dcf157a0 | |||
| 83a482de03 | |||
| 208f383925 | |||
| 05f9535a9b | |||
| c18fd9c44e | |||
| 07fa302d43 | |||
| 4a2b27f54a | |||
| ff507ea16a | |||
| 639196f0c9 | |||
| 404cb2d98c | |||
| 665d808660 | |||
| 15027fef29 | |||
| 26ae12f638 | |||
| 56393380b9 | |||
| d51d1a1266 | |||
| af5599ba54 | |||
| ce8017c6d2 | |||
| b64f8ddffa | |||
| e926d562c0 | |||
| 064adbc0b7 | |||
| 4872b95c43 | |||
| 4547dd5681 | |||
| 655ac1404a | |||
| 521d768635 | |||
| f736c46b81 | |||
| f537b99d02 | |||
| ad4b03871e | |||
| 4ef4bbd4ad | |||
| 2e44bfa09a | |||
| 424b4c6971 | |||
| 4130448a55 | |||
| ed6a6e5a34 | |||
| 36ccd48cfc | |||
| 61f2b376ee | |||
| b59888dc99 | |||
| d29e120c72 | |||
| 16cc43ad28 | |||
| 3773af632c | |||
| 2aeb58d9ed | |||
| affc7521d6 | |||
| f5a7d78d4f | |||
| c42c636231 | |||
| 99b21dbe8e | |||
| 3af4546839 | |||
| ace7801796 | |||
| 7d0a920c8c | |||
| f24f1ff4b7 | |||
| 703359301b | |||
| 66da50eb92 | |||
| 757a24894a | |||
| 4b19aabba6 | |||
| 626642cd25 | |||
| a1c91da619 | |||
| fac4169389 | |||
| a5f1ea1358 | |||
| db8df130fe | |||
| 52f4ab3157 | |||
| 8519d854fb | |||
| edd01e4445 | |||
| 9ea2820411 | |||
| 967818f315 | |||
| ca8e06f300 | |||
| a611b5010f | |||
| 2bc353c8fc | |||
| d4dd979311 | |||
| cd4bafbed3 | |||
| 51d7222c84 | |||
| 888df5c664 | |||
| 220394ed0d | |||
| 89280d6087 | |||
| cb3ad780b1 | |||
| 9615c940bb | |||
| 33e0fb21d6 | |||
| 2a8b2b3a40 | |||
| f765e1d38f | |||
| e6c011d007 | |||
| ba8aaa4ade | |||
| 9a93c6f983 | |||
| 803e9e00e0 | |||
| bb795a9555 | |||
| ac81aeed31 | |||
| 6a4d6d88c5 | |||
| 32ae7e2b38 | |||
| 4e62da3d52 | |||
| b19ae63ceb | |||
| 17c7e2446c | |||
| 1dab2c159a | |||
| 9cabb1053d | |||
| caa2f2d59c | |||
| 6a23042b74 | |||
| 33d13bb455 | |||
| 0074ad6643 | |||
| e2d3c05376 | |||
| c62f30ec32 | |||
| 536a108040 | |||
| c1525eaa60 | |||
| dcd2e1cd19 | |||
| 19865adb6a | |||
| b705e9e1e5 | |||
| 87a6a3f1f8 | |||
| 5914e2e578 | |||
| e39c7a47fc | |||
| 24c55e142b | |||
| de19519be0 | |||
| 3d87e928d4 | |||
| c89f338601 | |||
| 6feaddc542 | |||
| eaecbcf41f | |||
| 7b07b75747 | |||
| 0f397b0ee3 | |||
| 69918e681f | |||
| cb90b72836 | |||
| f5a6ffa8de | |||
| d3845601e9 | |||
| 1385472aaf | |||
| 5fd15c706b | |||
| 5bd502c72f | |||
| f39c4a51dd | |||
| 8e857abf29 | |||
| 2abd95da6d | |||
| 15a3697679 | |||
| a2d7299e72 | |||
| dcdda64b9e | |||
| 5cc5b04b18 | |||
| 0c87d0cc65 | |||
| a7ea5780cc | |||
| 6f06fc9503 | |||
| 6bc1f2d05f | |||
| c736041f3c | |||
| 8a5ad04776 | |||
| 6a726a331d | |||
| b0fe5b4a44 | |||
| 0e4aaabb54 | |||
| 8ddbae5ee2 | |||
| cfa0dd5a9a | |||
| 5644789d64 | |||
| c7c8a96a57 | |||
| f73512107c | |||
| f8401d00a4 | |||
| b79037c055 | |||
| 8af9a55187 | |||
| 1b200f217b | |||
| c0e6d13a1f | |||
| 2b00e03999 | |||
| bf2dabe3f4 | |||
| d0f549ce22 | |||
| 89165e9d88 | |||
| a601e93d00 | |||
| fa4d275cc0 | |||
| 9867d4f232 | |||
| e3b3484905 | |||
| def393b930 | |||
| c1096e2b01 | |||
| 04e1dad952 | |||
| e170bafffc | |||
| 23f31a8c4d | |||
| d5a5375379 | |||
| 7d520d864e | |||
| 16063402be | |||
| 0520592fc5 | |||
| f27a25fdf5 | |||
| 0181a703f9 | |||
| aad7967402 | |||
| 7814c0323e | |||
| eb1ee09769 | |||
| 5265f3e83c | |||
| 5aa03f88dc | |||
| ff2a56ac12 | |||
| 51ce3374b9 | |||
| 16576fd1f6 | |||
| 3ff52465dd | |||
| 0e9f8e2dd6 | |||
| 4225f3c8da | |||
| fff8c26df9 | |||
| 7d8a986784 | |||
| 4e25b796ca | |||
| 581c1c0c0a | |||
| 8d1b6b114a | |||
| 75ca9d485d | |||
| 74dc86d56c | |||
| 3e3c866ec0 | |||
| 2b0c63a783 | |||
| 8386beac1d | |||
| dc9694fb32 | |||
| 70a155a0a7 | |||
| 673aaf1c13 | |||
| c059bc34d8 | |||
| f2a3552286 | |||
| f491fe517a | |||
| f6c8f4fae6 | |||
| b43ea19e1e | |||
| c6ff40e288 | |||
| 86509e2598 | |||
| adc5498641 | |||
| 74d779ee35 | |||
| cc25a91cf1 | |||
| 13c909f085 | |||
| 2823433f7c | |||
| abfb28dea2 | |||
| ebac73704b | |||
| 74f1df6893 | |||
| 1ef4c22ec6 | |||
| 262516d3da | |||
| 1304c5180f | |||
| c3cabed6e7 | |||
| 274b79f293 | |||
| aa76b5ad79 | |||
| 84496271c4 | |||
| ac4670492e | |||
| aaed0c2547 | |||
| ed13289934 | |||
| a575ecdd68 | |||
| 0a2a4c68fa | |||
| d9692da89c | |||
| fbbc8d2d8b | |||
| d27186a177 | |||
| 812d59e4dd | |||
| 995c258aa5 | |||
| bd9af70a97 | |||
| 465c40b927 | |||
| 6f11b8c453 | |||
| 86ec9e9d54 | |||
| 78fe3e7956 | |||
| ad8a8c3cac | |||
| 46596fc5f6 | |||
| f09bbf8d4a | |||
| 83e0f1cda5 | |||
| aa4f63a8ce | |||
| 499a10837f | |||
| 405ccd1709 | |||
| b735c95c84 | |||
| e61a0f1de9 | |||
| 52b013e165 | |||
| 76081fd88f | |||
| 4a9649f096 | |||
| 061b6986a3 | |||
| ff49052baa | |||
| 7bd5255c63 | |||
| 473f4b19f0 |
@@ -5,3 +5,6 @@ indent_size = 2
|
||||
|
||||
[*.{md,markdown,mdx}]
|
||||
max_line_length = 80
|
||||
|
||||
[{Makefile,*.mk}]
|
||||
indent_style = tab
|
||||
|
||||
@@ -26,3 +26,4 @@ pnpm-debug.log*
|
||||
**/*.tfstate.backup
|
||||
|
||||
*.sqlite
|
||||
DIGITALOCEAN_TOKEN
|
||||
|
||||
@@ -1,36 +1,13 @@
|
||||
#############
|
||||
# VARIABLES #
|
||||
#############
|
||||
include make/vars.mk
|
||||
|
||||
CPU_ARCH := $(shell lscpu | grep ^Architecture: | sed "s/^Architecture:[[:space:]]*\([[:alnum:][:punct:]]\+\).*/\1/")
|
||||
IMAGE_PREFIX := $(if $(filter armv7%,$(CPU_ARCH)),armv7/)
|
||||
REGISTRY_DOMAIN := git.joeac.net
|
||||
REGISTRY_USER := joeac
|
||||
MODULES := http gemini smtp
|
||||
|
||||
|
||||
#############
|
||||
# FUNCTIONS #
|
||||
#############
|
||||
|
||||
container_image_name = $(REGISTRY_DOMAIN)/$(REGISTRY_USER)/joeac.net-$(module)
|
||||
|
||||
define build_module_rule =
|
||||
.PHONY: build_$(module)
|
||||
build_$(module): make_$(module) $(module).Dockerfile
|
||||
sudo podman-compose build $(module)
|
||||
endef
|
||||
|
||||
define push_module_rule =
|
||||
.PHONY: push_$(module)
|
||||
push_$(module): login_registry build_$(module)
|
||||
sudo podman push $(container_image_name)
|
||||
endef
|
||||
submake_file = $(shell [ -f "$(module)/Makefile" ] && echo "$(module)/Makefile")
|
||||
install_submake_file = $(shell [ -f "$(module)/install.mk" ] && echo "$(module)/install.mk")
|
||||
|
||||
define make_module_rule =
|
||||
.PHONY: make_$(module)
|
||||
make_$(module): $(module)/.env
|
||||
$(MAKE) --directory=$(module)
|
||||
$(if $(submake_file),\
|
||||
$(MAKE) --makefile=$(notdir $(submake_file)) --directory=$(module))
|
||||
endef
|
||||
|
||||
define module_env_rule =
|
||||
@@ -38,22 +15,52 @@ $(module)/.env: .env
|
||||
cp .env $(module)/.env
|
||||
endef
|
||||
|
||||
define install_module_rule =
|
||||
.PHONY: install_$(module)
|
||||
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)
|
||||
endef
|
||||
|
||||
#########
|
||||
# RULES #
|
||||
#########
|
||||
define reinstall_module_rule =
|
||||
.PHONY: reinstall_$(module)
|
||||
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)
|
||||
endef
|
||||
|
||||
all: $(foreach module,$(MODULES),push_$(module))
|
||||
define uninstall_module_rule =
|
||||
.PHONY: uninstall_$(module)
|
||||
uninstall_$(module): uninstall_openrc_$(module) uninstall_dyndns_$(module) $(if $(SUBDOMAIN_$(module)),install_tls_$(SUBDOMAIN_$(module)))
|
||||
$(if $(install_submake_file),\
|
||||
$(MAKE) --makefile=$(notdir $(install_submake_file)) --directory $(dir $(install_submake_file)) uninstall
|
||||
)
|
||||
endef
|
||||
|
||||
$(foreach module,$(MODULES),$(eval $(call build_module_rule)))
|
||||
$(foreach module,$(MODULES),$(eval $(call push_module_rule)))
|
||||
$(foreach module,$(MODULES),$(eval $(call make_module_rule)))
|
||||
$(foreach module,$(MODULES),$(eval $(call module_env_rule)))
|
||||
.PHONY: all
|
||||
all: $(ENV_RULES) $(MAKE_RULES) $(BUILD_RULES) $(PUSH_RULES)
|
||||
|
||||
.PHONY: login_registry
|
||||
login_registry:
|
||||
sudo podman login $(REGISTRY_DOMAIN)
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(call make_module_rule)))
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(call module_env_rule)))
|
||||
|
||||
.PHONY: install
|
||||
install: install_tls install_nginx $(ENV_RULES) $(INSTALL_RULES) install_crontab
|
||||
|
||||
.PHONY: reinstall
|
||||
reinstall: reinstall_tls reinstall_nginx reinstall_dyndns $(ENV_RULES) $(REINSTALL_RULES) reinstall_crontab
|
||||
|
||||
.PHONY: uninstall
|
||||
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 $(reinstall_module_rule)))
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(uninstall_module_rule)))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(foreach module,$(MODULES),$(MAKE) --directory=$(module) clean;)
|
||||
$(foreach module,$(MAKE_MODULES),$(MAKE) --directory=$(module) clean;)
|
||||
|
||||
include make/container.mk
|
||||
include make/openrc.mk
|
||||
include make/nginx.mk
|
||||
include make/crontab.mk
|
||||
include make/dyndns.mk
|
||||
include make/tls.mk
|
||||
|
||||
@@ -2,44 +2,103 @@
|
||||
|
||||
Joe Carstairs' public Internet presence
|
||||
|
||||
Structure:
|
||||
To install:
|
||||
|
||||
```
|
||||
/
|
||||
├── gemini My Gemini capsule
|
||||
├── smtp A local SMTP server
|
||||
└── http My Website
|
||||
```sh
|
||||
wget -O- https://git.joeac.net/joeac/joeac.net/raw/branch/main/install.sh | sh
|
||||
```
|
||||
|
||||
## Running with Podman
|
||||
## DNS setup
|
||||
|
||||
These instructions will probably work with Docker, too: just substitute `podman`
|
||||
for `docker` in all the commands.
|
||||
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.
|
||||
|
||||
To run with Podman, first set up your environment variables. Copy `example.env`
|
||||
to `.env` and edit the values accordingly.
|
||||
Deliver mail for mail.joeac.net to mail.joeac.net:
|
||||
|
||||
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
|
||||
```
|
||||
mail.joeac.net. MX 10 mail.joeac.net.
|
||||
```
|
||||
|
||||
Now build and start the containers:
|
||||
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:
|
||||
|
||||
```bash
|
||||
sudo podman-compose build && sudo podman-compose up -d
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
## Running on the host machine
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
```bash
|
||||
npm run start
|
||||
```
|
||||
mail.joeac.net. TXT v=spf1 ip4:217.155.190.42 ip6:fdc9:6aec:7a18:0:2e0:4cff:fe61:9b17 mx ~all
|
||||
```
|
||||
|
||||
Note that emails may not work locally without further setup. These instructions
|
||||
are of course woefully incomplete.
|
||||
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.
|
||||
|
||||
```
|
||||
_dmarc.mail.joeac.net. TXT v=DMARC1;p=reject;rua=mailto:dmarcreports@mail.joeac.net!10m
|
||||
```
|
||||
|
||||
Remote servers can use MTA-STS to verify our TLS certificate with the WebPKI
|
||||
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"
|
||||
```
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
I looked through some concordances while I was bored in the New College Library the other day.
|
||||
|
||||
I really love Robert Young's Analytical Concordance. Young's is a concordance to the Authorised Version, so the entries are the English words used in the AV. But each English-language entry groups together all the words in the Greek New Testament and Hebrew Old Testament which correspond to that English word, and lists all the occurrences of each of those words in their respective source texts. That makes it a perfect tool for understanding the relationships between the biblical source texts. The only disadvantage is that it doesn't seem at all interested in the Septuagint, which is really important for understanding the way New Testament authors use the Old Testament.
|
||||
|
||||
It astonished me that there are concordances available of the NIV and ESV texts. Why would you want that? The texts don't correspond very well to the Greek or Hebrew source texts, and they don't have nearly as much clout as self-standing faith texts as the Authorised Version does. I really don't get it. If I had one, I would probably never open it.
|
||||
|
||||
I couldn't get ahold of a Strong's, but I did happen to drop in Armchair Books on the way back from the library, and they have a beautiful 19th-century Cruden's Concordance. Cruden's was the first English-language concordance when its eponymous author painstakingly constructed it in 1737, and has never been out of print since then. By the looks of it, it remains very relevant for English-speaking readers of the Bible. And going for a bargain as well... if you get there before me, I'll eat your head.
|
||||
@@ -0,0 +1,7 @@
|
||||
So I've now got half a dozen services running on my homelab across two machines. I need to install the services on each machine, keep them running after crashes and reboots, update and restart them when the source code changes, and co-ordinate them with each other (since I can only have one public IP on my home network, but I want to serve stuff over the Internet from both machines).
|
||||
|
||||
I am currently managing this with Podman, some Dockerfiles and Docker-Compose files, Makefiles, and a lot of manual interference. This just about works, and is probably reasonably sensible for the small, low-consequence situation.
|
||||
|
||||
Still, it is a faff. I'm wondering: is this kind of what Kubernetes is for? I've never understood. Looking at the documentation, I find it really hard to understand what Kubernetes is for. Maybe it's for situations kind of like this (only typically much bigger)?
|
||||
|
||||
Answers on a postcard please.
|
||||
@@ -0,0 +1,11 @@
|
||||
Writing is hard! I've just spent 2 days fixing 1 paragraph in my dissertation. The problem was to give the reader good reason to think that the fossil fuel industry exerts a strong influence on the majority epistemology. The end result is a single paragraph with four citations. You'd think that would take half a day, not 2 full days.
|
||||
|
||||
I think what made it hard was that I needed to gain understanding. If I just needed a fact or two, it would have been easier: skim a few abstracts, extract a few figures, call it a day. But I didn't know in advance what fossil-think looks like. I couldn't write a paragraph that was almost done but for a few missing statistics. I needed to know the whens, the hows, the whos.
|
||||
|
||||
What I ended up doing was collecting a score of browser tabs with relevant articles and ebooks (which was easy enough), then going through each one and reading it: properly reading it, for understanding, not just skimming abstracts.
|
||||
|
||||
This worked: after about half a dozen articles, I reviewed my notes, realised I had enough to be getting on with, and wrote up my paragraph. Along the way I gained a (very shallow) understanding of how the fossil fuel industry influences public discourse.
|
||||
|
||||
But: it took a heck of a long time for one paragraph.
|
||||
|
||||
I really wish I had an experienced researcher looking over my shoulder, popping by a couple of times a day, to offer advice. Maybe they would tell me: sorry, that's just how it is, you need to gain understanding and that takes time. Or maybe they would say: you should really be cutting the corner here, let me show you how. It's one of the many things you cannot get from a monthly check-in with a supervisor.
|
||||
@@ -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
|
||||
+69
-12
@@ -1,38 +1,95 @@
|
||||
services:
|
||||
actualbudget:
|
||||
image: docker.io/actualbudget/actual-server:latest-alpine
|
||||
container_name: joeac.net-actualbudget
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ${ACTUALBUDGET_DATA_DIR}:/data/
|
||||
ports:
|
||||
- "${ACTUALBUDGET_PORT}:5006"
|
||||
|
||||
gemini:
|
||||
image: git.joeac.net/joeac/joeac.net-gemini
|
||||
image: git.joeac.net/joeac/${IMAGE_PREFIX}joeac.net-gemini
|
||||
container_name: joeac.net-gemini
|
||||
build:
|
||||
context: .
|
||||
dockerfile: gemini.Dockerfile
|
||||
ports:
|
||||
- "1965:1965"
|
||||
- "${GEMINI_PORT}:1965"
|
||||
volumes:
|
||||
- ${GEMINI_CERTIFICATES_DIR}:/var/app/.certificates
|
||||
- ${GEMINI_COMITIUM_DATA_DIR}:/var/app/comitium-data
|
||||
|
||||
http:
|
||||
image: git.joeac.net/joeac/joeac.net-http
|
||||
image: git.joeac.net/joeac/${IMAGE_PREFIX}joeac.net-http
|
||||
container_name: joeac.net-http
|
||||
build:
|
||||
context: .
|
||||
dockerfile: http.Dockerfile
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
MAX_DAILY_EMAILS: ${MAX_DAILY_EMAILS}
|
||||
CONTACT_MAILBOX: ${CONTACT_MAILBOX}
|
||||
CONTACT_MAILBOX_NAME: ${CONTACT_MAILBOX_NAME}
|
||||
LOCAL_SMTP_FROM: ${LOCAL_SMTP_FROM}
|
||||
LOCAL_SMTP_FROM_NAME: ${LOCAL_SMTP_FROM_NAME}
|
||||
LOCAL_SMTP_HOST: ${LOCAL_SMTP_HOST}
|
||||
LOCAL_SMTP_PORT: ${LOCAL_SMTP_PORT}
|
||||
LOCAL_SMTP_USER: ${LOCAL_SMTP_USER}
|
||||
LOCAL_SMTP_PASSWORD: ${LOCAL_SMTP_PASSWORD}
|
||||
DB_SCHEME: ${DB_SCHEME}
|
||||
DB_PATH: ${DB_PATH}
|
||||
ports:
|
||||
- "8080:80"
|
||||
- "${HTTP_PORT}:80"
|
||||
|
||||
etherpad:
|
||||
image: git.joeac.net/joeac/${IMAGE_PREFIX}joeac.net-etherpad
|
||||
container_name: joeac.net-etherpad
|
||||
build:
|
||||
context: .
|
||||
dockerfile: etherpad.Dockerfile
|
||||
args:
|
||||
ALPINE_VERSION: ${ALPINE_VERSION}
|
||||
ETHERPAD_VERSION: ${ETHERPAD_VERSION}
|
||||
volumes:
|
||||
- ${ETHERPAD_DATA_DIR}:/var/app/var
|
||||
environment:
|
||||
NODE_ENV: ${ETHERPAD_NODE_ENV}
|
||||
ADMIN_PASSWORD: ${ETHERPAD_ADMIN_PASSWORD}
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${ETHERPAD_PORT}:9001"
|
||||
|
||||
smtp:
|
||||
image: git.joeac.net/joeac/joeac.net-smtp
|
||||
image: git.joeac.net/joeac/${IMAGE_PREFIX}joeac.net-smtp
|
||||
container_name: joeac.net-smtp
|
||||
build:
|
||||
context: .
|
||||
dockerfile: smtp.Dockerfile
|
||||
args:
|
||||
LOCAL_SMTP_PORT: 2500
|
||||
env_file:
|
||||
- .env
|
||||
SMTP_PORT: ${LOCAL_SMTP_PORT}
|
||||
environment:
|
||||
LOCAL_SMTP_PORT: 2500
|
||||
LOCAL_SMTP_PASSWORD: smtp
|
||||
LOCAL_SMTP_ENVELOPE_FROM: ${LOCAL_SMTP_ENVELOPE_FROM}
|
||||
REMOTE_SMTP_HOST: ${REMOTE_SMTP_HOST}
|
||||
REMOTE_SMTP_PORT: ${REMOTE_SMTP_PORT}
|
||||
REMOTE_SMTP_USER: ${REMOTE_SMTP_USER}
|
||||
SMTP_PORT: ${LOCAL_SMTP_PORT}
|
||||
SMTP_USER: ${LOCAL_SMTP_USER}
|
||||
SMTP_PASSWORD: ${LOCAL_SMTP_PASSWORD}
|
||||
REMOTE_SMTP_PASSWORD_FILE: /run/secrets/remote_smtp_password
|
||||
secrets:
|
||||
- remote_smtp_password
|
||||
|
||||
vaultwarden:
|
||||
image: docker.io/vaultwarden/server:latest
|
||||
container_name: joeac.net-vaultwarden
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
DOMAIN: "https://pwd.joeac.net"
|
||||
volumes:
|
||||
- ${VAULTWARDEN_DATA_DIR}:/data/
|
||||
ports:
|
||||
- "${VAULTWARDEN_PORT}:80"
|
||||
|
||||
secrets:
|
||||
remote_smtp_password:
|
||||
external: true
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
ARG ALPINE_VERSION=3.23
|
||||
FROM docker.io/alpine:${ALPINE_VERSION}
|
||||
RUN mkdir -p /var/app
|
||||
WORKDIR /var/app
|
||||
ARG ETHERPAD_VERSION
|
||||
RUN apk --no-cache add pnpm \
|
||||
&& ENV=~/.profile SHELL=sh pnpm setup \
|
||||
&& source ~/.profile \
|
||||
&& pnpm install --global tsx
|
||||
COPY etherpad/etherpad-${ETHERPAD_VERSION} .
|
||||
CMD pnpx tsx src/node/server.ts
|
||||
@@ -0,0 +1,2 @@
|
||||
var
|
||||
etherpad-*
|
||||
@@ -0,0 +1,27 @@
|
||||
ETHERPAD_VERSION := 3.3.2
|
||||
SRC_DIR := etherpad-$(ETHERPAD_VERSION)
|
||||
|
||||
.PHONY: all
|
||||
all: download_etherpad install_deps
|
||||
|
||||
.PHONY: download_etherpad
|
||||
download_etherpad: $(SRC_DIR)
|
||||
|
||||
$(SRC_DIR):
|
||||
wget -O- https://github.com/ether/etherpad/archive/refs/tags/v3.3.2.tar.gz | tar -xz
|
||||
|
||||
.PHONY: install_deps
|
||||
install_deps: $(SRC_DIR)/node_modules
|
||||
|
||||
$(SRC_DIR)/node_modules: $(SRC_DIR) $(SRC_DIR)/settings.json $(SRC_DIR)/package.json $(SRC_DIR)/pnpm-lock.yaml
|
||||
cd $(SRC_DIR) && pnpm install
|
||||
|
||||
$(SRC_DIR)/settings.json: $(SRC_DIR) settings.json.template
|
||||
ifdef ETHERPAD_PORT
|
||||
ETHERPAD_PORT=$(ETHERPAD_PORT) envsubst -no-unset -i settings.json.template -o $(SRC_DIR)/settings.json
|
||||
else
|
||||
$(error ETHERPAD_PORT is not defined)
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -rf etherpad-*/
|
||||
@@ -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)
|
||||
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"title": "joeac's docs",
|
||||
"showRecentPads": true,
|
||||
"favicon": null,
|
||||
"skinName": "colibris",
|
||||
"skinVariants": "super-light-toolbar super-light-editor light-background",
|
||||
"ip": "0.0.0.0",
|
||||
"port": ${ETHERPAD_PORT},
|
||||
"showSettingsInAdminPage": true,
|
||||
"enableMetrics": "$${ENABLE_METRICS:true}",
|
||||
"cleanup": {
|
||||
"enabled": false,
|
||||
"keepRevisions": 5
|
||||
},
|
||||
"dbType": "sqlite",
|
||||
"dbSettings": {
|
||||
"filename": "var/etherpad.sq3"
|
||||
},
|
||||
"defaultPadText" : "",
|
||||
"padOptions": {
|
||||
"noColors": false,
|
||||
"showControls": true,
|
||||
"showChat": true,
|
||||
"showLineNumbers": true,
|
||||
"useMonospaceFont": false,
|
||||
"userName": null,
|
||||
"userColor": null,
|
||||
"rtl": false,
|
||||
"alwaysShowChat": false,
|
||||
"chatAndUsers": false,
|
||||
"lang": null
|
||||
},
|
||||
"padShortcutEnabled" : {
|
||||
"altF9": true,
|
||||
"altC": true,
|
||||
"cmdShift2": true,
|
||||
"delete": true,
|
||||
"return": true,
|
||||
"esc": true,
|
||||
"cmdS": true,
|
||||
"tab": true,
|
||||
"cmdZ": true,
|
||||
"cmdY": true,
|
||||
"cmdI": true,
|
||||
"cmdB": true,
|
||||
"cmdU": true,
|
||||
"cmd5": true,
|
||||
"cmdShiftL": true,
|
||||
"cmdShiftN": true,
|
||||
"cmdShift1": true,
|
||||
"cmdShiftC": true,
|
||||
"cmdH": true,
|
||||
"ctrlHome": true,
|
||||
"pageUp": true,
|
||||
"pageDown": true
|
||||
},
|
||||
"updateServer": "https://etherpad.org/ep_infos",
|
||||
"suppressErrorsInPadText": false,
|
||||
"requireSession": false,
|
||||
"editOnly": false,
|
||||
"minify": true,
|
||||
"maxAge": 21600,
|
||||
"soffice": null,
|
||||
"docxExport": true,
|
||||
"allowUnknownFileEnds": true,
|
||||
"requireAuthentication": false,
|
||||
"requireAuthorization": false,
|
||||
"trustProxy": false,
|
||||
"cookie": {
|
||||
"keyRotationInterval": 86400000,
|
||||
"sameSite": "Lax",
|
||||
"sessionLifetime": 864000000,
|
||||
"sessionRefreshInterval": 86400000,
|
||||
"sessionCleanup": true
|
||||
},
|
||||
"disableIPlogging": false,
|
||||
"automaticReconnectionTimeout": 0,
|
||||
"scrollWhenFocusLineIsOutOfViewport": {
|
||||
"percentage": {
|
||||
"editionAboveViewport": 0,
|
||||
"editionBelowViewport": 0
|
||||
},
|
||||
"duration": 0,
|
||||
"scrollWhenCaretIsInTheLastLineOfViewport": false,
|
||||
"percentageToScrollWhenUserPressesArrowUp": 0
|
||||
},
|
||||
"users": {
|
||||
"admin": {
|
||||
"password": "admin",
|
||||
"is_admin": true
|
||||
}
|
||||
},
|
||||
"socketTransportProtocols" : ["websocket", "polling"],
|
||||
"socketIo": {
|
||||
"maxHttpBufferSize": 1000000
|
||||
},
|
||||
"loadTest": false,
|
||||
"dumpOnUncleanExit": false,
|
||||
"importExportRateLimiting": {
|
||||
"windowMs": 90000,
|
||||
"max": 10
|
||||
},
|
||||
"importMaxFileSize": 52428800, // 50 * 1024 * 1024
|
||||
"authenticationMethod": "$${AUTHENTICATION_METHOD:sso}",
|
||||
"enableDarkMode": "$${ENABLE_DARK_MODE:true}",
|
||||
"enablePadWideSettings": "$${ENABLE_PAD_WIDE_SETTINGS:false}",
|
||||
"commitRateLimiting": {
|
||||
"duration": 1,
|
||||
"points": 10
|
||||
},
|
||||
"logLayoutType": "colored",
|
||||
"customLocaleStrings": {},
|
||||
"enableAdminUITests": false,
|
||||
"lowerCasePadIds": false,
|
||||
"sso": {
|
||||
"issuer": "$${SSO_ISSUER:http://localhost:${ETHERPAD_PORT}}",
|
||||
"clients": [
|
||||
{
|
||||
"client_id": "$${ADMIN_CLIENT:admin_client}",
|
||||
"client_secret": "$${ADMIN_SECRET:admin}",
|
||||
"grant_types": ["authorization_code"],
|
||||
"response_types": ["code"],
|
||||
"redirect_uris": ["$${ADMIN_REDIRECT:http://localhost:${ETHERPAD_PORT}/admin/}"]
|
||||
},
|
||||
{
|
||||
"client_id": "$${USER_CLIENT:user_client}",
|
||||
"client_secret": "$${USER_SECRET:user}",
|
||||
"grant_types": ["authorization_code"],
|
||||
"response_types": ["code"],
|
||||
"redirect_uris": ["$${USER_REDIRECT:http://localhost:${ETHERPAD_PORT}/}"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+11
-9
@@ -1,15 +1,11 @@
|
||||
# The hostname to use for the local SMTP server
|
||||
LOCAL_SMTP_HOST=
|
||||
|
||||
# The port to use for the local SMTP server
|
||||
LOCAL_SMTP_PORT=
|
||||
LOCAL_SMTP_HOST=smtp
|
||||
|
||||
# The username for authenticating to the local SMTP server
|
||||
# Recommended to be the same as REMOTE_SMTP_USER, else the remote may reject it
|
||||
LOCAL_SMTP_USER=
|
||||
LOCAL_SMTP_USER=smtp
|
||||
|
||||
# The password for authenticating to the local SMTP server
|
||||
LOCAL_SMTP_PASSWORD=
|
||||
LOCAL_SMTP_PASSWORD=smtp
|
||||
|
||||
# The envelope-from used by the local SMTP server
|
||||
# Theoretically should be "LOCAL_SMTP_FROM_NAME <LOCAL_SMTP_FROM>", but in
|
||||
@@ -44,7 +40,13 @@ CONTACT_MAILBOX_NAME=
|
||||
MAX_DAILY_EMAILS=
|
||||
|
||||
# The scheme part of the URI to the website database
|
||||
DB_SCHEME=
|
||||
DB_SCHEME=sqlite
|
||||
|
||||
# The path part of the URI to the website database
|
||||
DB_PATH=
|
||||
DB_PATH=/var/app/joeac.net-http.sqlite
|
||||
|
||||
# The Node.JS environment for the Etherpad instance (production, development)
|
||||
ETHERPAD_NODE_ENV=production
|
||||
|
||||
# The admin password for the Etherpad instance
|
||||
ETHERPAD_ADMIN_PASSWORD=
|
||||
|
||||
+6
-5
@@ -1,18 +1,19 @@
|
||||
FROM git.joeac.net/joeac/armv7/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/armv7/crond:1.37.0-r30-alpine3.23 AS final
|
||||
FROM git.joeac.net/joeac/${IMAGE_PREFIX}agate:3.3.20-alpine3.23 AS agate
|
||||
FROM git.joeac.net/joeac/${IMAGE_PREFIX}comitium:1.8.2-alpine3.23 AS comitium
|
||||
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
|
||||
COPY --from=agate /root/.cargo/bin/agate /usr/local/bin/agate
|
||||
COPY --from=comitium /usr/local/bin/comitium /usr/local/bin/comitium
|
||||
|
||||
RUN mkdir -p /var/app/content
|
||||
WORKDIR /var/app
|
||||
COPY gemini/.certificates .certificates
|
||||
RUN crontab -l > crontab.tmp \
|
||||
&& echo "0 */6 * * * /usr/local/bin/comitium refresh --data /var/app/comitium-data" >> crontab.tmp \
|
||||
&& crontab crontab.tmp \
|
||||
&& rm crontab.tmp
|
||||
|
||||
COPY gemini/content gemini/comitium-data /var/app/
|
||||
COPY gemini/run.sh /var/app/
|
||||
COPY gemini/content /var/app/content
|
||||
COPY common /var/common
|
||||
|
||||
CMD ./run.sh
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
GEMINI_COMITIUM_DATA_FILES := $(addprefix $(GEMINI_COMITIUM_DATA_DIR)/,$(notdir $(wildcard comitium-data/*)))
|
||||
|
||||
.PHONY: install
|
||||
install: $(GEMINI_CERTIFICATES_DIR) $(GEMINI_COMITIUM_DATA_FILES)
|
||||
|
||||
.PHONY: reinstall
|
||||
reinstall: $(GEMINI_CERTIFICATES_DIR) $(GEMINI_COMITIUM_DATA_FILES)
|
||||
|
||||
$(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)
|
||||
sudo cp $< $@
|
||||
$(let gemini_user,$(shell whoami),sudo chown $(gemini_user):$(gemini_user) $@)
|
||||
|
||||
$(GEMINI_COMITIUM_DATA_DIR):
|
||||
sudo mkdir -p $(GEMINI_COMITIUM_DATA_DIR)
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
sudo rm -rf $(GEMINI_COMITIUM_DATA_DIR)
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
make && \
|
||||
( ( sleep 5; comitium refresh --data comitium-data/ ) & ) \
|
||||
( ( sleep 5; comitium refresh --data comitium-data/ ) & ) \
|
||||
&& agate --content content/ --addr [::]:1965 --addr 0.0.0.0:1965 --lang en-GB
|
||||
|
||||
+9
-2
@@ -1,6 +1,13 @@
|
||||
FROM docker.io/arm32v7/nginx:1.30.3-alpine3.23
|
||||
RUN apk --update add php85-fpm
|
||||
RUN apk --update add php85-fpm php85-pdo php85-pdo_sqlite
|
||||
COPY http/vendor /usr/share/nginx/vendor
|
||||
COPY http/php /usr/share/nginx/php
|
||||
COPY http/out /usr/share/nginx/html
|
||||
COPY http/php-fpm.conf /etc/php/8.5/fpm/pool.d/joeac.net-http_pool.conf
|
||||
COPY http/php-fpm.conf /etc/php85/php-fpm.d/joeac.net-http_pool.conf
|
||||
COPY http/nginx.conf /etc/nginx/nginx.conf
|
||||
CMD mkdir -p "$(dirname "$DB_PATH")" \
|
||||
&& touch $DB_PATH \
|
||||
&& chown -R nginx:nginx "$(dirname "$DB_PATH")" \
|
||||
&& chmod -R 700 "$(dirname "$DB_PATH")" \
|
||||
&& php-fpm85 \
|
||||
&& nginx -g "daemon off;"
|
||||
|
||||
+51
-24
@@ -5,8 +5,7 @@ include config.mk
|
||||
# VARIABLES #
|
||||
#############
|
||||
|
||||
src_files := $(filter-out %.args,$(wildcard src/*.upp*))
|
||||
src_files += $(filter-out %.args,$(wildcard src/**/*.upp*))
|
||||
src_files := $(filter-out %.args,$(wildcard src/*.upp*)) $(filter-out %.args,$(wildcard src/**/*.upp*))
|
||||
src_files_ext := $(suffix $(src_files))
|
||||
out_deps_ext := $(src_files_ext:.upp%=%)
|
||||
|
||||
@@ -14,10 +13,12 @@ component_files := $(shell find -L share/components -type f)
|
||||
layout_files := $(wildcard share/layouts/*.layout.upp*)
|
||||
layouts := $(notdir $(basename $(basename $(layout_files))))
|
||||
|
||||
out_deps := $(addprefix out/,$(src_files:src/%=%))
|
||||
remove_layout_from_out_deps = out_deps := $$(subst $(1).upp,.,$$(out_deps))
|
||||
$(foreach layout,$(layouts),$(eval $(call remove_layout_from_out_deps,.$(layout))))
|
||||
$(eval $(call remove_layout_from_out_deps,))
|
||||
remove_all_layouts = $(call remove_layouts,$(layouts),$(1))
|
||||
remove_layouts = $(let first rest,$(1),$(call remove_layout,$(first),$(if $(rest),$(call remove_layouts,$(rest),$(2)),$(2))))
|
||||
remove_layout = $(subst .$(1).upp,.,$(2))
|
||||
out_deps := $(subst .upp,.,$(call remove_all_layouts,$(addprefix out/,$(src_files:src/%=%))))
|
||||
out_deps_without_src := $(filter-out $(out_deps),$(shell find -L out -type f))
|
||||
out_deps += $(out_deps_without_src)
|
||||
|
||||
blogs := $(subst blogs/,,$(wildcard blogs/*))
|
||||
|
||||
@@ -32,24 +33,25 @@ blog_src = $(patsubst \
|
||||
blogs/$(blog)/%.$(BLOG_EXT_$(blog)),\
|
||||
src/$(blog)/%$(if $(BLOG_LAYOUT_$(blog)),.$(BLOG_LAYOUT_$(blog))).upphtml,\
|
||||
$(shell find -L "blogs/$(blog)" -type f -and -name *.$(BLOG_EXT_$(blog))))
|
||||
blog_src_without_post_src = $(filter-out $(blog_src),$(shell find -L "src/$(blog)" -type f -and -name *.$(BLOG_LAYOUT_$(blog)).upphtml))
|
||||
default_layout_file = $(if \
|
||||
$(shell [ -f "share/layouts/default.layout.$(ext)" ] && echo 1),\
|
||||
share/layouts/default.layout.$(ext))
|
||||
layout_file = $(if $(layout),share/layouts/$(layout).layout.upp$(ext),$(default_layout_file))
|
||||
|
||||
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 $$<)"
|
||||
endef
|
||||
|
||||
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)"
|
||||
endef
|
||||
|
||||
define blog_rule =
|
||||
.PHONY: $(blog)
|
||||
$(blog): $(blog_src)
|
||||
$(blog): $(blog_src_without_post_src) $(blog_src) out/$(blog).html
|
||||
endef
|
||||
|
||||
define blog_post_rule =
|
||||
@@ -61,10 +63,35 @@ $(blog_post_target): $(blog_post_src) $(let ext,html,$(layout_file) $(component_
|
||||
-f $$*.$(BLOG_EXT_$(blog))
|
||||
endef
|
||||
|
||||
define prune_blog_rule =
|
||||
.PHONY: prune_$(blog)
|
||||
prune_$(blog):
|
||||
./bin/prune_blog $(blog) *$(if $(BLOG_LAYOUT_$(blog)),.$(BLOG_LAYOUT_$(blog))).upphtml
|
||||
define blog_index_rule =
|
||||
out/$(blog).html: src/$(blog).upphtml $(blog_src) $(wildcard bin/*) bin/pp
|
||||
./bin/mkws https://joeac.net "$$(realpath src/$(blog).upphtml)"
|
||||
endef
|
||||
|
||||
define prune_blog_src_file_rule =
|
||||
$(let rel_basename,$(patsubst src/$(blog)/%.$(BLOG_LAYOUT_$(blog)).upphtml,%,$(file)),
|
||||
blogs/$(blog)/$(rel_basename).$(BLOG_EXT_$(blog)):
|
||||
rm $(file)
|
||||
)
|
||||
endef
|
||||
|
||||
define prune_blog_out_file_rule =
|
||||
$(let rel_basename,$(patsubst src/$(blog)/%.$(BLOG_LAYOUT_$(blog)).upphtml,%,$(file)),
|
||||
$(file):
|
||||
rm out/$(rel_basename).html
|
||||
)
|
||||
endef
|
||||
|
||||
define prune_out_file_rule =
|
||||
$(let orig_ext,$(patsubst .%,%,$(suffix $(file))),
|
||||
$(let ext,$(patsubst upp%,%,$(orig_ext)),
|
||||
$(let rel_basename,$(patsubst out/%.$(orig_ext),%,$(file)),
|
||||
$(let src_file,src/$(rel_basename).upp$(ext),
|
||||
$(let src_files_with_layouts,$(foreach layout,$(layouts),src/$(rel_basename).$(layout).upp$(ext)),
|
||||
$(let public_file,public/$(rel_basename).$(orig_ext),
|
||||
$(src_file) $(src_files_with_layouts) $(public_file):
|
||||
rm $(file)
|
||||
))))))
|
||||
endef
|
||||
|
||||
|
||||
@@ -72,10 +99,8 @@ endef
|
||||
# RULES #
|
||||
#########
|
||||
|
||||
all: bin/pp prune $(blogs) public out
|
||||
|
||||
bin/pp:
|
||||
cd pp && $(MAKE) && cp pp ../bin/pp
|
||||
all: $(blogs) public out vendor
|
||||
$(MAKE) out # if blog posts have been pruned, outfiles must be re-calculated
|
||||
|
||||
share/man/man1/pp.1:
|
||||
cp pp/pp.1 share/man/man1/pp.1
|
||||
@@ -83,6 +108,9 @@ share/man/man1/pp.1:
|
||||
.PHONY: out
|
||||
out: $(out_deps)
|
||||
|
||||
bin/pp:
|
||||
$(MAKE) --directory=pp && chmod +x pp/pp && cp pp/pp bin/pp
|
||||
|
||||
$(foreach ext,$(sort $(out_deps_ext)),\
|
||||
$(eval $(out_rule)))
|
||||
$(foreach layout,$(layouts),\
|
||||
@@ -90,6 +118,7 @@ $(foreach layout,$(layouts),\
|
||||
$(eval $(out_rule))))
|
||||
|
||||
$(foreach blog,$(blogs),$(eval $(blog_rule)))
|
||||
$(foreach blog,$(blogs),$(eval $(blog_index_rule)))
|
||||
|
||||
$(foreach blog,$(blogs),\
|
||||
$(foreach layout,$(layouts),\
|
||||
@@ -105,18 +134,16 @@ public: $(subst public/,out/,$(shell find -L public/ -type f))
|
||||
out/%: public/%
|
||||
mkdir -p $(dir $@) && cp $< $@
|
||||
|
||||
.PHONY: prune
|
||||
prune: $(addprefix prune_,$(blogs)) prune_out
|
||||
$(foreach file,$(out_deps_without_src),$(eval $(prune_out_file_rule)))
|
||||
$(foreach blog,$(blogs),$(foreach file,$(blog_src_without_post_src),$(eval $(prune_blog_src_file_rule))))
|
||||
|
||||
.PHONY: prune_out
|
||||
prune_out:
|
||||
./bin/prune_out
|
||||
|
||||
$(foreach blog,$(blogs),$(eval $(prune_blog_rule)))
|
||||
vendor: composer.json composer.lock
|
||||
composer install
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf \
|
||||
vendor \
|
||||
out \
|
||||
$(foreach blog,$(blogs), \
|
||||
$(foreach ext,upphtml upphtml.args,\
|
||||
|
||||
+2
-2
@@ -102,8 +102,8 @@ do
|
||||
export POST_TITLE="$name"
|
||||
cat "$entry" | eval "${postprocess_cmd}" > "$dest"
|
||||
else
|
||||
export POST_TITLE="$(grep --regexp "^# " --max-count 1 "$entry" | cut -c3-)"
|
||||
cat "$entry" | grep --regexp "^# " --invert-match | eval "$postprocess_cmd" > "$dest"
|
||||
export POST_TITLE="$(grep -e "^# " -m 1 "$entry" | cut -c3-)"
|
||||
cat "$entry" | grep -e "^# " -v | eval "$postprocess_cmd" > "$dest"
|
||||
fi
|
||||
cat "$entry" | eval "$extract_args_cmd" > "${dest}.args"
|
||||
echo "Processed ${entry#$(dirname ${BLOGS})/} to ${dest#$(dirname ${SRC})/}"
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
BLOG="$1"
|
||||
BLOG_POST_PATTERN="${2:-*}"
|
||||
|
||||
SRC="$(realpath src)"
|
||||
BLOGS="$(realpath blogs)"
|
||||
LAYOUTS="$(realpath share/layouts)"
|
||||
BLOG_DIR_IN_SRC="${SRC}/${BLOG}"
|
||||
BLOG_EXT=gmi
|
||||
|
||||
for post in $(find "$BLOG_DIR_IN_SRC" -type f -and -name "$BLOG_POST_PATTERN")
|
||||
do
|
||||
last_segment="${post##*\.}"
|
||||
if [ "$last_segment" = "args" ]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
|
||||
post_rel_path="$(echo "$post" | cut -c${#BLOG_DIR_IN_SRC}- | cut -c3-)"
|
||||
post_basename_len=$(( ${#post_rel_path} - ( ${#last_segment} + 1 ) ))
|
||||
post_basename="$(echo "${post_rel_path}" | cut -c1-${post_basename_len})"
|
||||
post_src="${BLOGS}/${BLOG}/${post_basename}.${BLOG_EXT}"
|
||||
if [ -f "$post_src" ]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
|
||||
penultimate_segment_len=$(( ${#post} - ( ${#last_segment} + 1 ) ))
|
||||
penultimate_segment="$(echo "${post}" | cut -c1-${penultimate_segment_len})"
|
||||
penultimate_segment="${penultimate_segment##*\.}"
|
||||
post_basename_len=$(( ${#post_rel_path} - ( ${#last_segment} + ${#penultimate_segment} + 2 ) ))
|
||||
post_basename="$(echo "${post_rel_path}" | cut -c1-${post_basename_len})"
|
||||
if [ -f "${LAYOUTS}/${penultimate_segment}.layout.${last_segment}" ]
|
||||
then
|
||||
post_src="${BLOGS}/${BLOG}/${post_basename}.${BLOG_EXT}"
|
||||
if [ -f "$post_src" ]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "No source file found to match post ${post} in blog ${BLOG}: removing ${post}"
|
||||
rm -f "$post" "${post}.args"
|
||||
done
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
for out in $(find out -type f)
|
||||
do
|
||||
out_basename="$(basename "$out")"
|
||||
out_ext="${out_basename##*\.}"
|
||||
rel_path="$(echo "${out}" | cut -c5-)"
|
||||
|
||||
if [ -f "public/${rel_path}" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
base_rel_path="${rel_path%%.${out_ext}}"
|
||||
src_path="src/${base_rel_path}.upp${out_ext}"
|
||||
if [ -f "$src_path" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
for layout in $(find share/layouts -name "*.layout.upp${out_ext}"); do
|
||||
layout="$(basename "$layout")"
|
||||
layout="$(echo ${layout} | cut -c1-$(( ${#layout} - 15 )) )"
|
||||
rel_path="$(echo "${out}" | cut -c5-)"
|
||||
base_rel_path="${rel_path%%.${out_ext}}"
|
||||
src_path="src/${base_rel_path}.${layout}.upp${out_ext}"
|
||||
if [ -f "$src_path" ]; then
|
||||
continue 2
|
||||
fi
|
||||
done
|
||||
|
||||
echo "No source file found to match ${out}: removing it"
|
||||
rm "$out"
|
||||
done
|
||||
Generated
+5
-5
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "752c91265ea3414ab13b2ff0f8925706",
|
||||
"content-hash": "5145609ea1f80d6d838d0f9649acd36a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "phpmailer/phpmailer",
|
||||
@@ -92,10 +92,10 @@
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.3.0"
|
||||
"platform": {},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.9.0"
|
||||
}
|
||||
|
||||
+20
-20
@@ -17,31 +17,31 @@ http {
|
||||
access_log /var/log/nginx/access.log main;
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name joeac.net;
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name joeac.net;
|
||||
|
||||
access_log /var/log/nginx/host.access.log main;
|
||||
access_log /var/log/nginx/host.access.log main;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri $uri.html $uri/index.html $uri.php $uri/index.php;
|
||||
}
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri $uri.html $uri/index.html $uri.php $uri/index.php =404;
|
||||
}
|
||||
|
||||
error_page 404 /error.html;
|
||||
error_page 404 /error.html;
|
||||
|
||||
location ~ \.php$ {
|
||||
root html;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
location ~ \.php$ {
|
||||
root html;
|
||||
fastcgi_pass unix:/run/php8.5-fpm-joeac.net-http.sock;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
location ~ /\.sqlite {
|
||||
deny all;
|
||||
location ~ /\.sqlite {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
-1
@@ -1,11 +1,17 @@
|
||||
[joeac.net]
|
||||
user = nginx
|
||||
group = nginx
|
||||
listen = /run/php/php8.1-fpm-joeac.net-http.sock
|
||||
listen = /run/php8.5-fpm-joeac.net-http.sock
|
||||
listen.owner = nginx
|
||||
listen.group = nginx
|
||||
listen.mode = 0660
|
||||
|
||||
access.log = /var/log/php85/$pool.access.log
|
||||
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{milli}d %{kilo}M %C%%"
|
||||
catch_workers_output = yes
|
||||
php_admin_value[error_log] = /var/log/php85/$pool.error.log
|
||||
php_admin_flag[log_errors] = on
|
||||
|
||||
php_admin_value[disable_functions] = exec,passthru,shell_exec,system
|
||||
php_admin_flag[allow_url_fopen] = off
|
||||
|
||||
@@ -15,3 +21,16 @@ pm.start_servers = 4
|
||||
pm.min_spare_servers = 2
|
||||
pm.max_spare_servers = 8
|
||||
pm.max_requests = 500
|
||||
|
||||
clear_env = no
|
||||
env[MAX_DAILY_EMAILS] = $MAX_DAILY_EMAILS
|
||||
env[CONTACT_MAILBOX] = $CONTACT_MAILBOX
|
||||
env[CONTACT_MAILBOX_NAME] = $CONTACT_MAILBOX_NAME
|
||||
env[LOCAL_SMTP_FROM] = $LOCAL_SMTP_FROM
|
||||
env[LOCAL_SMTP_FROM_NAME] = $LOCAL_SMTP_FROM_NAME
|
||||
env[LOCAL_SMTP_HOST] = $LOCAL_SMTP_HOST
|
||||
env[LOCAL_SMTP_PORT] = $LOCAL_SMTP_PORT
|
||||
env[LOCAL_SMTP_USER] = $LOCAL_SMTP_USER
|
||||
env[LOCAL_SMTP_PASSWORD] = $LOCAL_SMTP_PASSWORD
|
||||
env[DB_SCHEME] = $DB_SCHEME
|
||||
env[DB_PATH] = $DB_PATH
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!
|
||||
SITE_URL="${1}"
|
||||
#!
|
||||
<meta http-equiv="refresh" content="0" ; url="${SITE_URL}/subscribe" />
|
||||
<meta http-equiv=refresh content=0;url=${SITE_URL}/subscribe />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!
|
||||
SITE_URL="${1}"
|
||||
#!
|
||||
<meta http-equiv="refresh" content="0" ; url="${SITE_URL}/microlog/rss.xml" />
|
||||
<meta http-equiv=refresh content=0;url=${SITE_URL}/microlog/rss.xml />
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
#!/bin/sh
|
||||
|
||||
get_var_value()
|
||||
{
|
||||
expr "$(env | grep "^${1}=")" : "${1}=\(.*\)\$"
|
||||
}
|
||||
|
||||
if [ -z "$(which podman 2>/dev/null)" ]
|
||||
then
|
||||
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
|
||||
|
||||
while read line
|
||||
do
|
||||
if expr "${line}" : "[[:alnum:]_]\+=" 1>/dev/null
|
||||
then
|
||||
var_name="$(expr "${line}" : "\([[:alnum:]_]\+\)=")"
|
||||
|
||||
if [ -n "$(grep "^${var_name}=" /home/joeac.net/joeac.net/.env)" ]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ -z "$(get_var_value ${var_name})" ]
|
||||
then
|
||||
default_value="$(expr "${line}" : "[[:alnum:]_]\+=\(.*\)\$")"
|
||||
read -sp "${var_name}: " ${var_name}
|
||||
if [ -z "$(get_var_value ${var_name})" ]
|
||||
then
|
||||
eval ${var_name}="${default_value}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "${var_name}=$(get_var_value ${var_name})" >> /home/joeac.net/joeac.net/.env
|
||||
fi
|
||||
done </home/joeac.net/joeac.net/example.env
|
||||
|
||||
make --directory=/home/joeac.net/joeac.net
|
||||
make --directory=/home/joeac.net/joeac.net install
|
||||
@@ -0,0 +1,14 @@
|
||||
.PHONY: install
|
||||
install: $(PUBLIC_ROOT_DIR_ln)
|
||||
|
||||
.PHONY: reinstall
|
||||
reinstall: install
|
||||
|
||||
$(PUBLIC_ROOT_DIR_ln): public
|
||||
sudo rm -rf $(PUBLIC_ROOT_DIR_ln)
|
||||
sudo mkdir -p $(PUBLIC_ROOT_DIR_ln)
|
||||
sudo cp -r public/ $(PUBLIC_ROOT_DIR_ln)/
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
sudo rm -rf $(PUBLIC_ROOT_DIR_ln)
|
||||
@@ -0,0 +1 @@
|
||||
<meta http-equiv="refresh" content="0;url=https://forms.zohopublic.eu/mejo1/form/MilehousehutJuly2026/formperma/Jzvv9p6KIJxon5_kc2l29tI0FiMjKy3bJ5ICS9K67NQ" />
|
||||
@@ -0,0 +1,28 @@
|
||||
REGISTRY_DOMAIN := git.joeac.net
|
||||
REGISTRY_USER := joeac
|
||||
|
||||
container_image_name = $(shell $(COMPOSE_CMD) config | yq ".services.$(module).image")
|
||||
is_containerised = $(filter $(COMPOSE_SERVICES),$(module))
|
||||
is_own_image = $(filter git.joeac.net/%,$(container_image_name))
|
||||
has_dockerfile = $(shell test -f $(module).Dockerfile)
|
||||
|
||||
define build_module_rule =
|
||||
.PHONY: build_$(module)
|
||||
build_$(module): $(if $(is_containerised),make_$(module) $(if $(has_dockerfile),$(module).Dockerfile))
|
||||
$(if $(is_containerised),\
|
||||
$(COMPOSE_CMD) build $(module))
|
||||
endef
|
||||
|
||||
define push_module_rule =
|
||||
.PHONY: push_$(module)
|
||||
push_$(module): $(if $(is_containerised),login_registry)
|
||||
$(if $(is_containerised),$(if $(is_own_image),\
|
||||
podman push $(container_image_name)))
|
||||
endef
|
||||
|
||||
$(foreach module,$(MODULES),$(eval $(call build_module_rule)))
|
||||
$(foreach module,$(MODULES),$(eval $(call push_module_rule)))
|
||||
|
||||
.PHONY: login_registry
|
||||
login_registry:
|
||||
podman login $(REGISTRY_DOMAIN)
|
||||
@@ -0,0 +1,13 @@
|
||||
.PHONY: install_crontab
|
||||
install_crontab: /etc/periodic/daily/joeac.net
|
||||
|
||||
.PHONY: reinstall_crontab
|
||||
reinstall_crontab: /etc/periodic/daily/joeac.net
|
||||
|
||||
.PHONY: uninstall_crontab
|
||||
uninstall_crontab:
|
||||
sudo rm -f /etc/periodic/daily/joeac.net
|
||||
|
||||
/etc/periodic/daily/joeac.net: update.sh
|
||||
sudo cp update.sh /etc/periodic/daily/joeac.net
|
||||
sudo chmod +x /etc/periodic/daily/joeac.net
|
||||
@@ -0,0 +1,55 @@
|
||||
installed_dyndns_crontabs = $(wildcard /etc/periodic/daily/dyndns-*.joeac.net)
|
||||
installed_dyndns_subdomains = $(installed_dyndns_crontabs:/etc/periodic/daily/dyndns-%.joeac.net=%)
|
||||
dyndns_subdomains_to_remove = $(filter-out $(SUBDOMAINS),$(installed_dyndns_subdomains))
|
||||
dyndns_crontabs_to_remove = $(dyndns_subdomains_to_remove:%=/etc/periodic/daily/dyndns-%.joeac.net)
|
||||
|
||||
define install_dyndns_module_rule =
|
||||
.PHONY: install_dyndns_$(module)
|
||||
install_dyndns_module_$(module): $(if $(SUBDOMAIN_$(module)),/etc/periodic/daily/dyndns-$(SUBDOMAIN_$(module)).joeac.net)
|
||||
endef
|
||||
|
||||
define reinstall_dyndns_module_rule =
|
||||
.PHONY: reinstall_dyndns_$(module)
|
||||
reinstall_dyndns_$(module): $(if $(SUBDOMAIN_$(module)),/etc/periodic/daily/dyndns-$(SUBDOMAIN_$(module)).joeac.net reinstall_dyndns)
|
||||
endef
|
||||
|
||||
define uninstall_dyndns_module_rule =
|
||||
.PHONY: uninstall_dyndns_$(module)
|
||||
uninstall_dyndns_$(module):
|
||||
$(if $(SUBDOMAIN_$(module)), \
|
||||
sudo rm -f /etc/periodic/daily/dyndns-$(SUBDOMAIN_$(module)).joeac.net
|
||||
)
|
||||
endef
|
||||
|
||||
$(foreach module,$(ALL_MODULES), $(eval $(install_dyndns_module_rule)))
|
||||
$(foreach module,$(ALL_MODULES), $(eval $(reinstall_dyndns_module_rule)))
|
||||
$(foreach module,$(ALL_MODULES), $(eval $(uninstall_dyndns_module_rule)))
|
||||
|
||||
.PHONY: remove_/etc/periodic/daily/dyndns-%.joeac.net
|
||||
remove_/etc/periodic/daily/dyndns-%.joeac.net:
|
||||
rm -f $(@:remove_%=%)
|
||||
|
||||
/etc/periodic/daily/dyndns-%joeac.net: ~/digitalocean_dyndns/dyndns.sh ~/.config/dyndns/DIGITALOCEAN_TOKEN
|
||||
echo "#!/bin/sh" > crontab.tmp
|
||||
echo " $(shell realpath ~)/digitalocean_dyndns/dyndns.sh 4 $(*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 chmod +x $@
|
||||
|
||||
.PHONY: reinstall_dyndns
|
||||
reinstall_dyndns: $(addprefix remove_,$(dyndns_crontabs_to_remove))
|
||||
|
||||
.PHONY: uninstall_dyndns
|
||||
uninstall_dyndns: $(foreach module,$(ALL_MODULES),$(uninstall_dyndns_$(module)))
|
||||
sudo rm -rf \
|
||||
~/digitalocean_dyndns/ \
|
||||
~/.config/dyndns \
|
||||
~/.cache/dyndns
|
||||
|
||||
~/digitalocean_dyndns/%:
|
||||
git clone https://git.joeac.net/joeac/digitalocean_dyndns.git ~/digitalocean_dyndns
|
||||
|
||||
~/.config/dyndns/DIGITALOCEAN_TOKEN: DIGITALOCEAN_TOKEN
|
||||
mkdir -p ~/.config/dyndns/
|
||||
rm -f ~/.config/dyndns/DIGITALOCEAN_TOKEN
|
||||
cp DIGITALOCEAN_TOKEN ~/.config/dyndns/DIGITALOCEAN_TOKEN
|
||||
@@ -0,0 +1,75 @@
|
||||
installed_nginx_sites = $(wildcard /etc/nginx/http.d/*.joeac.net.conf)
|
||||
installed_nginx_subdomains = $(installed_nginx_sites:/etc/nginx/http.d/%.joeac.net.conf=%)
|
||||
nginx_subdomains_to_remove = $(filter-out $(NGINX_SUBDOMAINS),$(installed_nginx_subdomains))
|
||||
nginx_sites_to_remove = $(nginx_subdomains_to_remove:%=/etc/nginx/http.d/%.joeac.net.conf)
|
||||
nginx_module_config_template = \
|
||||
$(if $(PORT_$(module)),nginx/http.d/reverse_proxy.conf.template) \
|
||||
$(if $(PUBLIC_ROOT_DIR_$(module)),nginx/http.d/static.conf.template)
|
||||
nginx_module_config_template_args = \
|
||||
CERTNAME=$(SUBDOMAIN_$(module)).joeac.net \
|
||||
DOMAIN=$(if $(filter-out @,$(SUBDOMAIN_$(module))),$(SUBDOMAIN_$(module)).)joeac.net \
|
||||
$(if $(PORT_$(module)),PORT=$(PORT_$(module)) HOST=$(HOST_$(module))) \
|
||||
$(if $(PUBLIC_ROOT_DIR_$(module)),ROOT="$(PUBLIC_ROOT_DIR_$(module))")
|
||||
|
||||
define install_nginx_module_rule =
|
||||
.PHONY: install_nginx_$(module)
|
||||
install_nginx_$(module): $(if $(SUBDOMAIN_$(module)),/etc/nginx/http.d/$(SUBDOMAIN_$(module)).joeac.net.conf)
|
||||
endef
|
||||
|
||||
define reinstall_nginx_module_rule =
|
||||
.PHONY: reinstall_nginx_$(module)
|
||||
reinstall_nginx_$(module): $(if $(SUBDOMAIN_$(module)),/etc/nginx/http.d/$(SUBDOMAIN_$(module)).joeac.net.conf)
|
||||
endef
|
||||
|
||||
define uninstall_nginx_module_rule =
|
||||
.PHONY: uninstall_nginx_$(module)
|
||||
uninstall_nginx_$(module):
|
||||
$(if $(SUBDOMAIN_$(module)),sudo rm -f /etc/nginx/http.d/$(SUBDOMAIN_$(module)).joeac.net.conf)
|
||||
endef
|
||||
|
||||
define remove_nginx_site_rule =
|
||||
remove_$(site):
|
||||
sudo rm -f $(site)
|
||||
endef
|
||||
|
||||
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
|
||||
$(nginx_module_config_template_args) envsubst -i $$< -o $$(notdir $$@).tmp
|
||||
sudo cp $$(notdir $$@).tmp $$@
|
||||
sudo rc-service nginx restart
|
||||
endef
|
||||
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(install_nginx_module_rule)))
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(reinstall_nginx_module_rule)))
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(uninstall_nginx_module_rule)))
|
||||
$(foreach site,$(nginx_sites_to_remove),$(eval $(remove_nginx_site_rule)))
|
||||
$(foreach module,$(ALL_NGINX_MODULES),$(eval $(nginx_module_config_rule)))
|
||||
|
||||
/etc/nginx/http.d:
|
||||
sudo mkdir -p /etc/nginx/http.d
|
||||
|
||||
.PHONY: remove_/etc/nginx/http.d/%.joeac.net.conf
|
||||
remove_/etc/nginx/http.d/%.joeac.net.conf:
|
||||
rm -f $(@:remove_%=%)
|
||||
|
||||
.PHONY: install_nginx
|
||||
install_nginx: /etc/nginx/nginx.conf $(addprefix install_nginx_,$(NGINX_MODULES))
|
||||
|
||||
.PHONY: reinstall_nginx
|
||||
reinstall_nginx: /etc/nginx/nginx.conf $(add_prefix reinstall_nginx_,$(NGINX_MODULES)) $(addprefix remove_,$(nginx_sites_to_remove))
|
||||
|
||||
.PHONY: uninstall_nginx
|
||||
uninstall_nginx: $(foreach module,$(NGINX_MODULES),uninstall_nginx_$(module))
|
||||
ifeq ($(shell test -d /etc/nginx/nginx.joeac.net-backup && echo 1 || echo 0),0)
|
||||
$(warn No nginx backup config detected: doing nothing)
|
||||
else
|
||||
sudo mv /etc/nginx/nginx.joeac.net-backup /etc/nginx/nginx.conf
|
||||
sudo rc-service nginx restart
|
||||
endif
|
||||
|
||||
/etc/nginx/nginx.conf: nginx/nginx.conf /etc/nginx/nginx.joeac.net-backup
|
||||
sudo cp $< $@
|
||||
sudo rc-service nginx restart
|
||||
|
||||
/etc/nginx/nginx.joeac.net-backup:
|
||||
sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.joeac.net-backup
|
||||
@@ -0,0 +1,74 @@
|
||||
is_openrc_module = $(filter $(COMPOSE_SERVICES),$(module))
|
||||
openrc_module_target = $(if $(is_openrc_module),~/.config/rc/init.d/joeac.net.$(module))
|
||||
|
||||
define install_openrc_module_rule =
|
||||
.PHONY: install_openrc_$(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
|
||||
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)
|
||||
endef
|
||||
|
||||
define reinstall_openrc_module_rule =
|
||||
.PHONY: reinstall_openrc_$(module)
|
||||
reinstall_openrc_$(module): $(if $(is_openrc_module),$(openrc_module_target) openrc_restart_$(module))
|
||||
endef
|
||||
|
||||
define uninstall_openrc_module_rule =
|
||||
.PHONY: uninstall_openrc_$(module)
|
||||
uninstall_openrc_$(module):
|
||||
$(if $(is_openrc_module),\
|
||||
rc-service -U joeac.net.$(module) stop; \
|
||||
rc-update -U del joeac.net.$(module) default; \
|
||||
rm -f ~/.config/rc/init.d/joeac.net.$(module); \
|
||||
)
|
||||
endef
|
||||
|
||||
define openrc_add_rule =
|
||||
.PHONY: openrc_add_$(module)
|
||||
openrc_add_$(module):
|
||||
rc-update -U add joeac.net.$(module) default
|
||||
endef
|
||||
|
||||
define openrc_start_rule =
|
||||
.PHONY: openrc_start_$(module)
|
||||
openrc_start_$(module):
|
||||
rc-service -U joeac.net.$(module) start
|
||||
endef
|
||||
|
||||
define openrc_restart_rule =
|
||||
.PHONY: openrc_restart_$(module)
|
||||
openrc_restart_$(module):
|
||||
rc-service -U joeac.net.$(module) restart
|
||||
endef
|
||||
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(install_openrc_module_rule)))
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(reinstall_openrc_module_rule)))
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(uninstall_openrc_module_rule)))
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(openrc_add_rule)))
|
||||
$(foreach module,$(ALL_MODULES),$(eval $(openrc_start_rule)))
|
||||
$(foreach module,$(MODULES),$(eval $(openrc_restart_rule)))
|
||||
|
||||
~/.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; \
|
||||
mkdir -p ~/.config/rc/init.d; \
|
||||
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:
|
||||
mkdir -p ~/.config/rc/init.d
|
||||
|
||||
~/.config/rc/runlevels/default:
|
||||
mkdir -p ~/.config/rc/runlevels/default
|
||||
|
||||
/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
|
||||
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
|
||||
|
||||
.PHONY: uninstall_joeac.net_service
|
||||
rm ~/.config/rc/joeac.net
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
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 \
|
||||
--non-interactive \
|
||||
&& 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
|
||||
@@ -0,0 +1,91 @@
|
||||
capitalise = $(shell echo "$(1)" | tr '[:lower:]' '[:upper:]')
|
||||
|
||||
USER := $(shell whoami)
|
||||
HOSTNAME := $(shell cat /etc/hostname)
|
||||
HOSTNAMES := pi-broughton blade-canongate
|
||||
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))
|
||||
MODULES_pi-broughton := actualbudget http smtp vaultwarden ln
|
||||
MODULES_blade-canongate := etherpad gemini mox mox_clientsettings mox_autoconfig mox_mta_sts
|
||||
ALL_NGINX_MODULES := actualbudget http vaultwarden ln etherpad mox mox_clientsettings mox_autoconfig mox_mta_sts
|
||||
NGINX_MODULES := $(if $(IS_MASTER_NODE),$(ALL_NGINX_MODULES))
|
||||
MODULES := $(MODULES_$(HOSTNAME))
|
||||
ALL_MODULES := $(sort $(foreach hostname,$(HOSTNAMES),$(MODULES_$(hostname))))
|
||||
COMPOSE_SERVICES := $(shell podman-compose config \
|
||||
| yq ".services | keys" --output-format csv --csv-separator " ")
|
||||
MAKE_MODULES := $(foreach module,$(MODULES),\
|
||||
$(shell [ -f $(module)/Makefile ] && echo $(module)))
|
||||
|
||||
SUBDOMAIN_actualbudget := budget
|
||||
SUBDOMAIN_http := @
|
||||
SUBDOMAIN_vaultwarden := pwd
|
||||
SUBDOMAIN_etherpad := docs
|
||||
SUBDOMAIN_ln := ln
|
||||
SUBDOMAIN_mox := mail
|
||||
SUBDOMAIN_mox_autoconfig := autoconfig.mail
|
||||
SUBDOMAIN_mox_clientsettings := clientsettings.mail
|
||||
SUBDOMAIN_mox_mta_sts := mta-sts.mail
|
||||
|
||||
PORT_actualbudget := 5006
|
||||
PORT_etherpad := 9001
|
||||
PORT_http := 8080
|
||||
PORT_gemini := 1965
|
||||
PORT_mox := 81
|
||||
PORT_mox_autoconfig := $(PORT_mox)
|
||||
PORT_mox_clientsettings := $(PORT_mox)
|
||||
PORT_mox_mta_sts := $(PORT_mox)
|
||||
PORT_smtp := 2500
|
||||
PORT_vaultwarden := 9000
|
||||
|
||||
PUBLIC_ROOT_DIR_ln := /var/ln.joeac.net/public
|
||||
|
||||
export ACTUALBUDGET_DATA_DIR := /var/joeac.net-actualbudget/var
|
||||
export ETHERPAD_DATA_DIR := /var/etherpad/var
|
||||
export GEMINI_CERTIFICATES_DIR := /var/joeac.net-gemini/certificates
|
||||
export GEMINI_COMITIUM_DATA_DIR := /var/joeac.net-gemini/comitium-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 \
|
||||
export $(call capitalise,$(module))_PORT := $(PORT_$(module)))))
|
||||
$(foreach hostname,$(HOSTNAMES),$(foreach module,$(MODULES_$(hostname)),$(eval \
|
||||
export HOST_$(module) := $(if $(filter $(HOSTNAME),$(hostname)),127.0.0.1,$(IP_ADDR_$(hostname))))))
|
||||
|
||||
ALL_SUBDOMAINS := $(foreach module,$(ALL_MODULES),$(SUBDOMAIN_$(module)))
|
||||
SUBDOMAINS := $(if $(IS_MASTER_NODE),$(ALL_SUBDOMAINS))
|
||||
NGINX_SUBDOMAINS := $(foreach module,$(NGINX_MODULES),$(SUBDOMAIN_$(module)))
|
||||
|
||||
ENV_RULES := $(foreach module,$(MODULES),$(if $(shell test -d $(module) && echo 1),$(module)/.env))
|
||||
MAKE_RULES := $(foreach module,$(MAKE_MODULES),make_$(module))
|
||||
BUILD_RULES := $(foreach module,$(filter $(COMPOSE_SERVICES),$(MODULES)),build_$(module))
|
||||
PUSH_RULES := $(foreach module,$(filter $(COMPOSE_SERVICES),$(MODULES)),push_$(module))
|
||||
INSTALL_RULES := $(foreach module,$(MODULES),install_$(module))
|
||||
REINSTALL_RULES := $(foreach module,$(MODULES),reinstall_$(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), \
|
||||
$(if $(SUBDOMAIN_$(module)),, \
|
||||
$(error $(module) is declared as an nginx module, but SUBDOMAIN_$(module) is not set)))
|
||||
$(foreach module,$(ALL_NGINX_MODULES), \
|
||||
$(if $(PORT_$(module)) $(HOST_$(module)),,$(if $(PUBLIC_ROOT_DIR_$(module)),, \
|
||||
$(error $(module) is declared as an nginx module, but neither PUBLIC_ROOT_DIR_$(module), nor both PORT_$(module) and HOST_$(module), are set))))
|
||||
@@ -0,0 +1,2 @@
|
||||
config/dkim
|
||||
config/adminpasswd
|
||||
@@ -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.
|
||||
@@ -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:
|
||||
- zen.spamhaus.org
|
||||
- bl.spamcop.net
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,63 @@
|
||||
.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 ~/mox/data $(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 $< $@
|
||||
|
||||
~/mox/data:
|
||||
mkdir -p $@
|
||||
@@ -0,0 +1 @@
|
||||
nameserver: 127.0.0.1
|
||||
@@ -0,0 +1,20 @@
|
||||
server {
|
||||
server_name ${DOMAIN};
|
||||
location / {
|
||||
proxy_pass http://${HOST}:${PORT};
|
||||
}
|
||||
listen 443 ssl;
|
||||
ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
}
|
||||
|
||||
server {
|
||||
if ($$host = ${DOMAIN}) {
|
||||
return 301 https://$$host$$request_uri;
|
||||
}
|
||||
server_name ${DOMAIN};
|
||||
listen 80;
|
||||
return 404;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
server {
|
||||
server_name ${DOMAIN};
|
||||
location / {
|
||||
root ${ROOT};
|
||||
try_files $$uri $$uri.html $$uri/index.html =404;
|
||||
error_page 404 /index.html;
|
||||
}
|
||||
listen 443 ssl;
|
||||
ssl_certificate /etc/letsencrypt/live/${CERTNAME}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/${CERTNAME}/privkey.pem;
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
}
|
||||
|
||||
server {
|
||||
if ($$host = ${DOMAIN}) {
|
||||
return 301 https://$$host$$request_uri;
|
||||
} # managed by Certbot
|
||||
server_name ln.joeac.net;
|
||||
listen 80;
|
||||
return 404;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
|
||||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/avif avif;
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
font/woff woff;
|
||||
font/woff2 woff2;
|
||||
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/wasm wasm;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
# /etc/nginx/nginx.conf
|
||||
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
pcre_jit on;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
server_tokens off;
|
||||
client_max_body_size 1m;
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:2m;
|
||||
ssl_session_timeout 1h;
|
||||
gzip on;
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
access_log /var/log/nginx/access.log main;
|
||||
include /etc/nginx/http.d/*.conf;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
UID="$$(id -u ${USER})"
|
||||
if test -z "$${XDG_RUNTIME_DIR}"; then
|
||||
export XDG_RUNTIME_DIR=/tmp/xdg/"$${UID}"-xdg-runtime-dir
|
||||
if ! test -d "$${XDG_RUNTIME_DIR}"; then
|
||||
mkdir -p "$${XDG_RUNTIME_DIR}"
|
||||
chown -R ${USER}:${USER} "$${XDG_RUNTIME_DIR}"
|
||||
chmod -R 0700 "$${XDG_RUNTIME_DIR}"
|
||||
fi
|
||||
fi
|
||||
if ! test -f "$${XDG_RUNTIME_DIR}/openrc/softlevel"; then
|
||||
mkdir -p "$${XDG_RUNTIME_DIR}/openrc"
|
||||
touch "$${XDG_RUNTIME_DIR}/openrc/softlevel"
|
||||
chown -R ${USER}:${USER} "$${XDG_RUNTIME_DIR}"
|
||||
chmod -R 0700 "$${XDG_RUNTIME_DIR}"
|
||||
fi
|
||||
Executable
+65
@@ -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
|
||||
}
|
||||
+3
-2
@@ -1,4 +1,5 @@
|
||||
FROM git.joeac.net/joeac/armv7/msmtp:1.8.32-alpine3.23
|
||||
ARG LOCAL_SMTP_PORT
|
||||
EXPOSE $LOCAL_SMTP_PORT
|
||||
RUN apk --no-cache add gettext gnutls
|
||||
ARG SMTP_PORT
|
||||
EXPOSE $SMTP_PORT
|
||||
COPY smtp/.msmtprc ./
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/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 \
|
||||
&& sudo -u joeac.net git pull \
|
||||
&& sudo -u joeac.net make \
|
||||
&& sudo -u joeac.net make reinstall
|
||||
@@ -0,0 +1,13 @@
|
||||
.PHONY: install
|
||||
install: $(VAULTWARDEN_DATA_DIR)
|
||||
|
||||
.PHONY: reinstall
|
||||
reinstall: $(VAULTWARDEN_DATA_DIR)
|
||||
|
||||
$(VAULTWARDEN_DATA_DIR):
|
||||
sudo mkdir -p $(VAULTWARDEN_DATA_DIR)
|
||||
VAULTWARDEN_USER=$(whoami) && sudo chown $$VAULTWARDEN_USER:$$VAULTWARDEN_USER $(VAULTWARDEN_DATA_DIR)
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
$(info Nothing to do)
|
||||
Reference in New Issue
Block a user