Compare commits
8 Commits
df4caf48d0
...
7750141e65
| Author | SHA1 | Date |
|---|---|---|
|
|
7750141e65 | 2 months ago |
|
|
a7a66dcf3d | 2 months ago |
|
|
39cf4ac288 | 2 months ago |
|
|
401f0b76f8 | 2 months ago |
|
|
3b2c745bdd | 2 months ago |
|
|
21ba201b61 | 2 months ago |
|
|
eff4d8be98 | 2 months ago |
|
|
2a12904888 | 2 months ago |
65 changed files with 735 additions and 180 deletions
@ -0,0 +1,6 @@ |
|||||
|
[Unit] |
||||
|
Description=Pull quay.io/centos/centos:stream10 |
||||
|
Documentation=https://quay.io/centos/centos |
||||
|
|
||||
|
[Image] |
||||
|
Image=quay.io/centos/centos:stream10 |
||||
@ -0,0 +1,16 @@ |
|||||
|
[Unit] |
||||
|
Description=Discover the virtiofs tags made available by the hypervisor |
||||
|
RequiresMountsFor=/run |
||||
|
ConditionPathIsMountPoint=/run |
||||
|
|
||||
|
# Unless DefaultDependencies= is set to false, service units will implicitly |
||||
|
# have dependencies of type Requires= and After= on basic.target as well as |
||||
|
# dependencies of type Conflicts= and Before= on shutdown.target. |
||||
|
# |
||||
|
# So, we need to set DefaultDependencies to "no" to break the ordering cycle. |
||||
|
DefaultDependencies=no |
||||
|
|
||||
|
[Service] |
||||
|
Type=oneshot |
||||
|
ExecStart=/bin/bash -Eeuo pipefail -c 'shopt -s nullglob; mkdir -p /run/quadlets/base/virtiofs; for tagfile in /sys/fs/virtiofs/*/tag; do tag=$(<"$tagfile"); echo -n > "/run/quadlets/base/virtiofs/$tag"; done' |
||||
|
RemainAfterExit=yes |
||||
@ -1,3 +1,3 @@ |
|||||
LEGO_GLOBAL_ARGS=-a -m nicolas.masse@itix.fr -d changeme.example.tld --http |
LEGO_GLOBAL_ARGS=-a -m nicolas.masse@itix.fr -d changeme.example.tld --http |
||||
LEGO_RUN_ARGS= |
LEGO_RUN_ARGS= |
||||
LEGO_RENEW_ARGS=--days 30 --renew-hook=/etc/lego/hooks/flag-as-renewed.sh |
LEGO_RENEW_ARGS=--days 30 --renew-hook=/etc/lego/renew-hook/flag-as-renewed.sh |
||||
|
|||||
@ -0,0 +1,19 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
set -Eeuo pipefail |
||||
|
|
||||
|
# In development mode, it is not possible to get a certificate from Let's Encrypt, so we just create a self-signed certificate for localhost, so that other services can still use it. |
||||
|
mkdir -p /var/lib/quadlets/lego/certificates |
||||
|
if [ -f /var/lib/quadlets/lego/certificates/localhost.crt ] && [ -f /var/lib/quadlets/lego/certificates/localhost.key ]; then |
||||
|
renewal="yes" |
||||
|
else |
||||
|
renewal="no" |
||||
|
fi |
||||
|
|
||||
|
echo "Generating self-signed certificate for localhost..." |
||||
|
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /var/lib/quadlets/lego/certificates/localhost.key -out /var/lib/quadlets/lego/certificates/localhost.crt -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost" |
||||
|
|
||||
|
if [[ "$renewal" == "yes" ]]; then |
||||
|
echo "Flagging certificate as renewed..." |
||||
|
touch /var/lib/quadlets/lego/certificates/localhost.renewed |
||||
|
fi |
||||
@ -0,0 +1,18 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
set -Eeuo pipefail |
||||
|
|
||||
|
for hook in /etc/quadlets/lego/renew-hooks.d/*.sh; do |
||||
|
if [[ -x "$hook" ]]; then |
||||
|
echo "Running renew hook: $hook" |
||||
|
if ! "$hook"; then |
||||
|
echo "Error: Renew hook failed: $hook" >&2 |
||||
|
fi |
||||
|
else |
||||
|
echo "Skipping non-executable hook: $hook" |
||||
|
fi |
||||
|
done |
||||
|
|
||||
|
rm -f /var/lib/quadlets/lego/certificates/*.renewed |
||||
|
|
||||
|
exit 0 |
||||
@ -0,0 +1,7 @@ |
|||||
|
[Container] |
||||
|
# When in development mode, it is not possible to renew a certificate from Let's Encrypt, so we just skip the entrypoint. |
||||
|
Entrypoint=/bin/true |
||||
|
|
||||
|
[Service] |
||||
|
# And we update the self-signed certificate and flag it as renewed. |
||||
|
ExecStartPost=/etc/quadlets/lego/lego-dev.sh |
||||
@ -0,0 +1,7 @@ |
|||||
|
[Container] |
||||
|
# When in development mode, it is not possible to get a certificate from Let's Encrypt, so we just skip the entrypoint. |
||||
|
Entrypoint=/bin/true |
||||
|
|
||||
|
[Service] |
||||
|
# And we create a self-signed certificate for localhost, so that other services can still use it. |
||||
|
ExecStartPost=/etc/quadlets/lego/lego-dev.sh |
||||
@ -0,0 +1,5 @@ |
|||||
|
# Lego renewal hooks
|
||||
|
TARGET_LEGO_FILES = $(patsubst other/lego/%.sh, $(TARGET_CHROOT)/etc/quadlets/lego/renew-hooks.d/%.sh, $(wildcard other/lego/*.sh)) |
||||
|
TARGET_FILES += $(TARGET_LEGO_FILES) |
||||
|
$(TARGET_CHROOT)/etc/quadlets/lego/renew-hooks.d/%.sh: other/lego/%.sh |
||||
|
install -D -m 0755 -o root -g root $< $@ |
||||
@ -0,0 +1,12 @@ |
|||||
|
[Unit] |
||||
|
Description=Process Lego certificate renewal hooks |
||||
|
# Lego touches .renewed files when renewed certificates are available |
||||
|
ConditionPathExistsGlob=/var/lib/quadlets/lego/certificates/*.renewed |
||||
|
After=lego-renew.service |
||||
|
|
||||
|
[Service] |
||||
|
Type=oneshot |
||||
|
ExecStart=/etc/quadlets/lego/process-hooks.sh |
||||
|
|
||||
|
[Install] |
||||
|
WantedBy=lego-renew.service |
||||
@ -0,0 +1,6 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
set -Eeuo pipefail |
||||
|
|
||||
|
/etc/quadlets/quay/quay_load_tls_certs.sh |
||||
|
systemctl --no-block restart quay-app.service |
||||
@ -1,15 +0,0 @@ |
|||||
[Unit] |
|
||||
Description=Initialize Quay TLS certificates if not already present |
|
||||
Before=quay-app.service |
|
||||
After=lego.target |
|
||||
|
|
||||
# Start/stop this unit when the target is started/stopped |
|
||||
PartOf=quay.target |
|
||||
|
|
||||
[Service] |
|
||||
Type=oneshot |
|
||||
RemainAfterExit=yes |
|
||||
ExecStart=/etc/quadlets/quay/quay_load_tls_certs.sh |
|
||||
|
|
||||
[Install] |
|
||||
WantedBy=quay.target |
|
||||
@ -1,17 +0,0 @@ |
|||||
[Unit] |
|
||||
Description=Reload Quay TLS certificate after Lego renewal |
|
||||
# Lego touches .renewed files when renewed certificates are available |
|
||||
ConditionPathExistsGlob=/var/lib/quadlets/lego/certificates/*.renewed |
|
||||
After=lego-renew.service |
|
||||
|
|
||||
[Service] |
|
||||
Type=oneshot |
|
||||
# Copy the renewed certificates to the Quay TLS directory |
|
||||
ExecStart=/etc/quadlets/quay/quay_load_tls_certs.sh |
|
||||
# Restart Quay to load the new certificate |
|
||||
ExecStart=systemctl --no-block restart quay-app.service |
|
||||
# Remove the flag files after restarting Quay |
|
||||
ExecStartPost=/bin/sh -Eeuo pipefail -c 'rm -f /var/lib/quadlets/lego/certificates/*.renewed' |
|
||||
|
|
||||
[Install] |
|
||||
WantedBy=lego-renew.service |
|
||||
@ -0,0 +1,9 @@ |
|||||
|
variant: fcos |
||||
|
version: 1.4.0 |
||||
|
passwd: |
||||
|
users: |
||||
|
- name: redis |
||||
|
uid: 10021 |
||||
|
gecos: Redis server |
||||
|
home_dir: /var/lib/quadlets/redis |
||||
|
primary_group: itix-svc |
||||
@ -1,19 +0,0 @@ |
|||||
server string = Storage |
|
||||
|
|
||||
[foo] |
|
||||
path = /data/foo |
|
||||
comment = Foo |
|
||||
valid users = @itix |
|
||||
write list = @itix |
|
||||
group = itix |
|
||||
directory mask = 0770 |
|
||||
create mask = 0660 |
|
||||
|
|
||||
[bar] |
|
||||
path = /data/bar |
|
||||
comment = Bar |
|
||||
valid users = @itix |
|
||||
write list = @itix |
|
||||
group = itix |
|
||||
directory mask = 0775 |
|
||||
create mask = 0664 |
|
||||
@ -0,0 +1,33 @@ |
|||||
|
[Unit] |
||||
|
Description=Fully automatic cross-seeding for torrent trackers |
||||
|
Documentation=https://www.cross-seed.org/docs/basics/getting-started |
||||
|
Wants=network.target |
||||
|
After=network.target |
||||
|
RequiresMountsFor=/var/lib/virtiofs/ssd |
||||
|
RequiresMountsFor=/var/lib/virtiofs/hdd |
||||
|
|
||||
|
[Container] |
||||
|
ContainerName=cross-seed |
||||
|
|
||||
|
# Image |
||||
|
Image=cross-seed.image |
||||
|
AutoUpdate=registry |
||||
|
|
||||
|
# Security |
||||
|
User=10017 |
||||
|
Group=10000 |
||||
|
|
||||
|
# Storage |
||||
|
Volume=/var/lib/virtiofs/ssd/cross-seed/config:/config:z |
||||
|
Volume=/var/lib/virtiofs/hdd:/data:z |
||||
|
|
||||
|
# Network |
||||
|
AddCapability=CAP_NET_BIND_SERVICE |
||||
|
Network=host |
||||
|
|
||||
|
# Configuration |
||||
|
Environment=TZ=Etc/UTC HOME=/config |
||||
|
Exec=daemon |
||||
|
|
||||
|
[Install] |
||||
|
WantedBy=seedbox.target |
||||
@ -0,0 +1,6 @@ |
|||||
|
[Unit] |
||||
|
Description=podman pull ghcr.io/cross-seed/cross-seed |
||||
|
Documentation=https://www.cross-seed.org/docs/basics/getting-started |
||||
|
|
||||
|
[Image] |
||||
|
Image=ghcr.io/cross-seed/cross-seed:latest |
||||
@ -0,0 +1,6 @@ |
|||||
|
[Unit] |
||||
|
RequiresMountsFor=/var/lib/virtiofs/ssd |
||||
|
RequiresMountsFor=/var/lib/virtiofs/hdd |
||||
|
|
||||
|
[Container] |
||||
|
Volume=/var/lib/virtiofs/hdd:/data:z |
||||
@ -0,0 +1,13 @@ |
|||||
|
http: |
||||
|
routers: |
||||
|
cross-seed: |
||||
|
rule: "Host(`cross-seed`)" |
||||
|
entryPoints: |
||||
|
- http |
||||
|
middlewares: |
||||
|
service: "cross-seed" |
||||
|
services: |
||||
|
cross-seed: |
||||
|
loadBalancer: |
||||
|
servers: |
||||
|
- url: "http://127.0.0.1:2468" |
||||
@ -1,22 +1,25 @@ |
|||||
d$ /var/lib/virtiofs/data/storage 0755 0 0 - |
d$ /var/lib/virtiofs/hdd/storage 0755 0 0 - |
||||
d$ /var/lib/virtiofs/data/storage/media 0775 10017 10000 - |
d$ /var/lib/virtiofs/hdd/storage/media 0775 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/storage/media/movies 0775 10017 10000 - |
d$ /var/lib/virtiofs/hdd/storage/media/movies 0775 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/storage/media/series 0775 10017 10000 - |
d$ /var/lib/virtiofs/hdd/storage/media/series 0775 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/storage/media/music 0775 10017 10000 - |
d$ /var/lib/virtiofs/hdd/storage/media/music 0775 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/storage/downloads 0775 10017 10000 - |
d$ /var/lib/virtiofs/hdd/storage/downloads 0775 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/storage/torrents 0775 10017 10000 - |
d$ /var/lib/virtiofs/hdd/storage/torrents 0775 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/storage/import 0775 10017 10000 - |
d$ /var/lib/virtiofs/hdd/storage/seed 0775 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/radarr 0700 10017 10000 - |
d$ /var/lib/virtiofs/hdd/storage/import 0775 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/radarr/config 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/radarr 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/radarr/config/tmp 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/radarr/config 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/radarr/config/xdg 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/radarr/config/tmp 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/sonarr 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/radarr/config/xdg 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/sonarr/config 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/sonarr 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/sonarr/config/tmp 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/sonarr/config 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/sonarr/config/xdg 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/sonarr/config/tmp 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/prowlarr 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/sonarr/config/xdg 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/prowlarr/config 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/prowlarr 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/prowlarr/config/tmp 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/prowlarr/config 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/prowlarr/config/xdg 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/prowlarr/config/tmp 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/jellyfin 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/prowlarr/config/xdg 0700 10017 10000 - |
||||
d$ /var/lib/virtiofs/data/jellyfin/config 0700 10017 10000 - |
d$ /var/lib/virtiofs/ssd/jellyfin 0700 10017 10000 - |
||||
|
d$ /var/lib/virtiofs/ssd/jellyfin/config 0700 10017 10000 - |
||||
|
d$ /var/lib/virtiofs/ssd/cross-seed 0700 10017 10000 - |
||||
|
d$ /var/lib/virtiofs/ssd/cross-seed/config 0700 10017 10000 - |
||||
|
|||||
@ -0,0 +1,16 @@ |
|||||
|
[Unit] |
||||
|
Description=Mount the "hdd" virtio filesystem |
||||
|
Requires=discover-virtiofs-tags.service |
||||
|
After=discover-virtiofs-tags.service |
||||
|
|
||||
|
# Only run if the "hdd" tag is present (as discovered by discover-virtiofs-tags.service) |
||||
|
ConditionPathExists=/run/quadlets/base/virtiofs/hdd |
||||
|
|
||||
|
[Mount] |
||||
|
What=hdd |
||||
|
Where=/var/lib/virtiofs/hdd |
||||
|
Type=virtiofs |
||||
|
Options=context=system_u:object_r:container_file_t:s0 |
||||
|
|
||||
|
[Install] |
||||
|
WantedBy=local-fs.target |
||||
@ -0,0 +1,16 @@ |
|||||
|
[Unit] |
||||
|
Description=Mount the "ssd" virtio filesystem |
||||
|
Requires=discover-virtiofs-tags.service |
||||
|
After=discover-virtiofs-tags.service |
||||
|
|
||||
|
# Only run if the "ssd" tag is present (as discovered by discover-virtiofs-tags.service) |
||||
|
ConditionPathExists=/run/quadlets/base/virtiofs/ssd |
||||
|
|
||||
|
[Mount] |
||||
|
What=ssd |
||||
|
Where=/var/lib/virtiofs/ssd |
||||
|
Type=virtiofs |
||||
|
Options=context=system_u:object_r:container_file_t:s0 |
||||
|
|
||||
|
[Install] |
||||
|
WantedBy=local-fs.target |
||||
@ -0,0 +1,12 @@ |
|||||
|
##
|
||||
|
## Makefile for smtprelay quadlet
|
||||
|
##
|
||||
|
|
||||
|
DEPENDENCIES = lego |
||||
|
|
||||
|
# smtprelay quadlet is mapped to the 10030 user (smtprelay) and 10000 group (itix-svc)
|
||||
|
PROJECT_UID = 10030 |
||||
|
PROJECT_GID = 10000 |
||||
|
|
||||
|
# Include common Makefile
|
||||
|
include ../../scripts/common.mk |
||||
@ -0,0 +1,68 @@ |
|||||
|
# Podman Quadlet: smtprelay |
||||
|
|
||||
|
## Overview |
||||
|
|
||||
|
[smtprelay](https://github.com/decke/smtprelay) is a small Golang based SMTP relay/proxy server that accepts mail via SMTP and forwards it to an upstream smarthost (ex: Mailgun, Gmail, ...). |
||||
|
|
||||
|
This cookbook: |
||||
|
|
||||
|
- Builds a custom smtprelay container image locally, from CentOS Stream 10. |
||||
|
- Runs smtprelay directly as a dedicated, unprivileged UID/GID (no user namespace mapping). |
||||
|
- Listens on the submission port (587) with STARTTLS, authenticating clients against a local user/password file. |
||||
|
- Loads TLS certificates issued by the `lego` cookbook and reloads them automatically when renewed. |
||||
|
- Includes a timer to periodically rebuild the container image. |
||||
|
|
||||
|
## Prerequisites |
||||
|
|
||||
|
- Configuration file `/etc/quadlets/smtprelay/smtprelay.ini` must exist. |
||||
|
- File `/etc/quadlets/smtprelay/allowed_users.txt` must exist, listing the users allowed to relay mail. |
||||
|
- The `lego` cookbook should be configured to provide TLS certificates. |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
In a separate terminal, follow the logs. |
||||
|
|
||||
|
```sh |
||||
|
sudo make tail-logs |
||||
|
``` |
||||
|
|
||||
|
Install the Podman Quadlets and start smtprelay. |
||||
|
|
||||
|
```sh |
||||
|
sudo make clean install |
||||
|
``` |
||||
|
|
||||
|
You should see the **smtprelay-build.service** building the smtprelay container image. |
||||
|
Then, the **smtprelay.service** should start up. |
||||
|
|
||||
|
Verify smtprelay is running: |
||||
|
|
||||
|
```sh |
||||
|
sudo systemctl status smtprelay.service |
||||
|
``` |
||||
|
|
||||
|
Send a test mail with [swaks](https://www.jetmore.org/john/code/swaks/): |
||||
|
|
||||
|
```sh |
||||
|
swaks --to youremail@example.com --from youremail@example.com --auth-user yourusername --auth-password yourpassword --port 587 --tls |
||||
|
``` |
||||
|
|
||||
|
When Let's Encrypt certificates are renewed, the renewal hook automatically restarts smtprelay so it picks up the new certificates. |
||||
|
|
||||
|
Restart the **smtprelay.target** unit. |
||||
|
|
||||
|
```sh |
||||
|
sudo systemctl restart smtprelay.target |
||||
|
``` |
||||
|
|
||||
|
Finally, remove the quadlets, their configuration and their data. |
||||
|
|
||||
|
```sh |
||||
|
sudo make uninstall clean |
||||
|
``` |
||||
|
|
||||
|
## Integration tests |
||||
|
|
||||
|
```sh |
||||
|
sudo make test |
||||
|
``` |
||||
@ -0,0 +1,73 @@ |
|||||
|
# Specification for smtprelay Quadlet Cookbook |
||||
|
|
||||
|
You will have to develop a Quadlet cookbook for smtprelay, the mail transfer agent. |
||||
|
|
||||
|
## Architecture |
||||
|
|
||||
|
smtprelay is a mail transfer agent, deployed as a container image. |
||||
|
The container image will be built from the CentOS Stream 10 image (`quay.io/centos/centos:stream10`). |
||||
|
|
||||
|
## Common requirements |
||||
|
|
||||
|
- The `quay.io/centos/centos:stream10` docker image MUST have its own quadlet .image file. |
||||
|
- Each cookbook MUST have a dedicated unique UID. The GID is 10000. |
||||
|
|
||||
|
## Security |
||||
|
|
||||
|
Directly set the UID and GID in the quadlet file (no mapping). |
||||
|
Use the host network, like other quadlet cookbooks. |
||||
|
Let's Encrypt certificates will be handled by Traefik, so no need to worry about that in the smtprelay cookbook. |
||||
|
|
||||
|
## Installation |
||||
|
|
||||
|
Create the Containerfile for smtprelay, which will install the smtprelay binary. |
||||
|
The smtprelay binary can be obtained from the official releases on GitHub: https://github.com/decke/smtprelay. |
||||
|
|
||||
|
Look at `cookbooks/base/config/install-fastfetch.sh` for an example of how to install a binary from a GitHub release in a Containerfile. |
||||
|
|
||||
|
## Configuration |
||||
|
|
||||
|
A sample configuration file for smtprelay: |
||||
|
|
||||
|
```ini |
||||
|
; Hostname for this SMTP server |
||||
|
hostname = localhost |
||||
|
|
||||
|
; File which contains username and password used for |
||||
|
; authentication before they can send mail. |
||||
|
allowed_users = /etc/smtprelay/allowed_users.txt |
||||
|
|
||||
|
; Networks that are allowed to send mails to us |
||||
|
; Defaults to localhost. If set to "", then any address is allowed. |
||||
|
;allowed_nets = 0.0.0.0/0 ::/0 |
||||
|
allowed_nets = 0.0.0.0/0 |
||||
|
|
||||
|
; Enable TLS for incoming connections on port 587 |
||||
|
listen = starttls://0.0.0.0:587 |
||||
|
local_cert = /etc/smtprelay/tls/localhost.crt |
||||
|
local_key = /etc/smtprelay/tls/localhost.key |
||||
|
|
||||
|
; Enforce encrypted connection on STARTTLS ports before |
||||
|
; accepting mails from client. |
||||
|
local_forcetls = true |
||||
|
|
||||
|
; Relay Config (ex: Mailgun) |
||||
|
remotes = starttls://user:pass@smtp.mailgun.org:587 |
||||
|
``` |
||||
|
|
||||
|
## Entrypoint |
||||
|
|
||||
|
```sh |
||||
|
smtprelay --config /etc/smtprelay/smtprelay.ini -logfile=/dev/stdout |
||||
|
``` |
||||
|
|
||||
|
## How to test |
||||
|
|
||||
|
```sh |
||||
|
swaks --to youremail@example.com --from youremail@example.com --auth-user yourusername --auth-password yourpassword --port 587 --tls |
||||
|
``` |
||||
|
|
||||
|
## Useful examples |
||||
|
|
||||
|
You can copy the structure of the `miniflux` cookbook. |
||||
|
Look at the `samba` cookbook for an example of how to handle the container image building. |
||||
@ -0,0 +1,22 @@ |
|||||
|
FROM quay.io/centos/centos:stream10 AS builder |
||||
|
|
||||
|
# Tools needed to fetch and unpack the smtprelay release |
||||
|
RUN dnf install -y curl jq tar gzip \ |
||||
|
&& dnf clean all |
||||
|
|
||||
|
COPY install-smtprelay.sh / |
||||
|
RUN /install-smtprelay.sh |
||||
|
|
||||
|
FROM quay.io/centos/centos:stream10 |
||||
|
|
||||
|
# CA certificates are required to establish TLS connections to the relay host |
||||
|
RUN dnf install -y ca-certificates \ |
||||
|
&& dnf clean all |
||||
|
|
||||
|
COPY --from=builder /usr/local/bin/smtprelay /usr/local/bin/smtprelay |
||||
|
|
||||
|
# Submission port |
||||
|
EXPOSE 587 |
||||
|
|
||||
|
ENTRYPOINT [ "/usr/local/bin/smtprelay" ] |
||||
|
CMD [ "--config", "/etc/smtprelay/smtprelay.ini", "-logfile=/dev/stdout" ] |
||||
@ -0,0 +1,9 @@ |
|||||
|
#!/bin/bash |
||||
|
set -Eeuo pipefail |
||||
|
SMTPRELAY_LATEST_VERSION="$(curl -sSfL https://api.github.com/repos/decke/smtprelay/releases | jq -r '.[] | select(.prerelease == false and .draft == false) | .tag_name' | sort -V | tail -1)" |
||||
|
SMTPRELAY_VERSION="${SMTPRELAY_VERSION:-$SMTPRELAY_LATEST_VERSION}" |
||||
|
declare -A ARCH_MAP=( ["x86_64"]="amd64" ["aarch64"]="arm64" ) |
||||
|
arch="$(arch)" |
||||
|
arch=${ARCH_MAP[$arch]} |
||||
|
echo "Installing smtprelay $SMTPRELAY_VERSION for $arch..." |
||||
|
curl -sSfL https://github.com/decke/smtprelay/releases/download/$SMTPRELAY_VERSION/smtprelay-$SMTPRELAY_VERSION-linux-$arch.tar.gz | tar -zx -C /usr/local/bin --no-same-owner smtprelay |
||||
@ -0,0 +1,16 @@ |
|||||
|
# File which contains username and password used for authentication |
||||
|
# before clients can relay mail through this server. |
||||
|
# |
||||
|
# Format (one user per line, fields separated by spaces): |
||||
|
# username bcrypt-hash [email[,email[,...]]] |
||||
|
# |
||||
|
# username: the SMTP auth username |
||||
|
# bcrypt-hash: the bcrypt hash of the password |
||||
|
# email: comma-separated list of "from" addresses the user is |
||||
|
# allowed to send as (omit to allow any address) |
||||
|
# |
||||
|
# Generate the bcrypt hash of a password with: |
||||
|
# python3 -c "import bcrypt; print(bcrypt.hashpw(b'<password>', bcrypt.gensalt()).decode())" |
||||
|
# |
||||
|
# Example user "demo" (password "changeme") allowed to send from any address: |
||||
|
demo $2b$12$V3XmeosOSoI4B.2D8HLzWu7y2YQaoBeF2unnGopZ2ZJJpQ58sKToa |
||||
@ -0,0 +1,42 @@ |
|||||
|
# ----------------------------------------------------------------------- |
||||
|
# smtprelay configuration - relay-only SMTP server |
||||
|
# |
||||
|
# Copy this file to /etc/quadlets/smtprelay/smtprelay.ini and adjust the |
||||
|
# values for your environment. |
||||
|
# ----------------------------------------------------------------------- |
||||
|
|
||||
|
; Hostname for this SMTP server |
||||
|
hostname = mail.example.com |
||||
|
|
||||
|
; File which contains username and password used for |
||||
|
; authentication before they can send mail (see allowed_users.txt example). |
||||
|
allowed_users = /etc/smtprelay/allowed_users.txt |
||||
|
|
||||
|
; Networks that are allowed to send mails to us. |
||||
|
; The container uses the host network, so clients connect from outside - |
||||
|
; allow any address and rely on SMTP authentication instead. |
||||
|
allowed_nets = 0.0.0.0/0 |
||||
|
|
||||
|
; ----------------------------------------------------------------------- |
||||
|
; Inbound TLS (certificates provided by the lego cookbook) |
||||
|
; |
||||
|
; Replace "localhost" with the actual certificate filename from |
||||
|
; /var/lib/quadlets/lego/certificates/. |
||||
|
; ----------------------------------------------------------------------- |
||||
|
|
||||
|
; Enable TLS for incoming connections on port 587 |
||||
|
listen = starttls://0.0.0.0:587 |
||||
|
local_cert = /etc/smtprelay/tls/localhost.crt |
||||
|
local_key = /etc/smtprelay/tls/localhost.key |
||||
|
|
||||
|
; Enforce encrypted connection on STARTTLS ports before |
||||
|
; accepting mails from client. |
||||
|
local_forcetls = true |
||||
|
|
||||
|
; ----------------------------------------------------------------------- |
||||
|
; Outbound relay |
||||
|
; ----------------------------------------------------------------------- |
||||
|
|
||||
|
; Relay all mail through an upstream smarthost (ex: Mailgun). |
||||
|
; Adjust the credentials and host for your provider. |
||||
|
remotes = starttls://user:pass@smtp.mailgun.org:587 |
||||
@ -0,0 +1,6 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
set -Eeuo pipefail |
||||
|
|
||||
|
install -o 10030 -g 10000 -m 0600 -t /run/quadlets/smtprelay/tls /var/lib/quadlets/lego/certificates/*.crt /var/lib/quadlets/lego/certificates/*.key |
||||
|
systemctl --no-block restart smtprelay.service |
||||
@ -0,0 +1,9 @@ |
|||||
|
variant: fcos |
||||
|
version: 1.4.0 |
||||
|
passwd: |
||||
|
users: |
||||
|
- name: smtprelay |
||||
|
uid: 10030 |
||||
|
gecos: smtprelay MTA |
||||
|
home_dir: /var/lib/quadlets/smtprelay |
||||
|
primary_group: itix-svc |
||||
@ -0,0 +1,10 @@ |
|||||
|
[Unit] |
||||
|
Description=Rebuild the smtprelay container image |
||||
|
PartOf=smtprelay.target |
||||
|
|
||||
|
[Timer] |
||||
|
OnCalendar=daily |
||||
|
Persistent=true |
||||
|
|
||||
|
[Install] |
||||
|
WantedBy=smtprelay.target |
||||
@ -0,0 +1,10 @@ |
|||||
|
[Unit] |
||||
|
Description=Build of the smtprelay MTA |
||||
|
Wants=network-online.target |
||||
|
After=network-online.target centos-stream10-image.service |
||||
|
Requires=centos-stream10-image.service |
||||
|
|
||||
|
[Build] |
||||
|
File=/etc/quadlets/smtprelay/container/Containerfile |
||||
|
ImageTag=localhost/smtprelay:latest |
||||
|
SetWorkingDirectory=/etc/quadlets/smtprelay/container |
||||
@ -0,0 +1,49 @@ |
|||||
|
[Unit] |
||||
|
Description=smtprelay MTA |
||||
|
Documentation=https://github.com/decke/smtprelay |
||||
|
After=local-fs.target network.target smtprelay-build.service lego.target |
||||
|
Wants=smtprelay-build.service lego.target |
||||
|
|
||||
|
# Only start if the main configuration file exists |
||||
|
ConditionPathExists=/etc/quadlets/smtprelay/smtprelay.ini |
||||
|
|
||||
|
# Stop when the target is stopped |
||||
|
PartOf=smtprelay.target |
||||
|
|
||||
|
[Container] |
||||
|
ContainerName=smtprelay |
||||
|
|
||||
|
# Image |
||||
|
Image=localhost/smtprelay:latest |
||||
|
AutoUpdate=local |
||||
|
|
||||
|
# Security - run directly as a dedicated, unprivileged UID/GID (no mapping) |
||||
|
User=10030 |
||||
|
Group=10000 |
||||
|
|
||||
|
# Port 587 is a privileged port (< 1024); grant the capability to bind to it |
||||
|
AddCapability=CAP_NET_BIND_SERVICE |
||||
|
|
||||
|
# Command and arguments |
||||
|
Entrypoint=/usr/local/bin/smtprelay |
||||
|
Exec=--config /etc/smtprelay/smtprelay.ini -logfile=/dev/stdout |
||||
|
|
||||
|
# Storage |
||||
|
Volume=/etc/quadlets/smtprelay/smtprelay.ini:/etc/smtprelay/smtprelay.ini:ro,Z |
||||
|
Volume=/etc/quadlets/smtprelay/allowed_users.txt:/etc/smtprelay/allowed_users.txt:ro,Z |
||||
|
Volume=/run/quadlets/smtprelay/tls:/etc/smtprelay/tls:Z |
||||
|
|
||||
|
# Network |
||||
|
Network=host |
||||
|
|
||||
|
[Service] |
||||
|
Restart=always |
||||
|
RestartSec=10 |
||||
|
TimeoutStartSec=120 |
||||
|
TimeoutStopSec=30 |
||||
|
|
||||
|
# Get the TLS certificates in place before starting smtprelay |
||||
|
ExecStartPre=/bin/sh -c 'install -o 10030 -g 10000 -m 0600 -t /run/quadlets/smtprelay/tls /var/lib/quadlets/lego/certificates/*.crt /var/lib/quadlets/lego/certificates/*.key' |
||||
|
|
||||
|
[Install] |
||||
|
WantedBy=smtprelay.target |
||||
@ -0,0 +1,11 @@ |
|||||
|
[Unit] |
||||
|
Description=smtprelay Service Target |
||||
|
Documentation=man:systemd.target(5) |
||||
|
Requires=smtprelay.service smtprelay-build.timer |
||||
|
After=smtprelay.service smtprelay-build.timer |
||||
|
|
||||
|
# Allow isolation - can stop/start this target independently |
||||
|
AllowIsolate=yes |
||||
|
|
||||
|
[Install] |
||||
|
WantedBy=multi-user.target |
||||
@ -0,0 +1,2 @@ |
|||||
|
d$ /run/quadlets/smtprelay 0700 10030 10000 - |
||||
|
d$ /run/quadlets/smtprelay/tls 0700 10030 10000 - |
||||
@ -0,0 +1,6 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
set -Eeuo pipefail |
||||
|
|
||||
|
install -o 10015 -g 10000 -m 0600 -t /run/quadlets/vsftpd/tls /var/lib/quadlets/lego/certificates/*.crt /var/lib/quadlets/lego/certificates/*.key |
||||
|
systemctl --no-block restart vsftpd.service |
||||
@ -1,17 +0,0 @@ |
|||||
[Unit] |
|
||||
Description=Restart Vsftpd if a new TLS certificate is available |
|
||||
# Lego touch .renewed files when renewed certificates are available |
|
||||
ConditionPathExistsGlob=/var/lib/quadlets/lego/certificates/*.renewed |
|
||||
After=lego-renew.service |
|
||||
|
|
||||
[Service] |
|
||||
Type=oneshot |
|
||||
# Copy the renewed certificates to the vsftpd /run directory |
|
||||
ExecStartPre=/bin/sh -Eeuo pipefail -c 'install -o 10015 -g 10000 -m 0600 -t /run/quadlets/vsftpd/tls /var/lib/quadlets/lego/certificates/*.crt /var/lib/quadlets/lego/certificates/*.key' |
|
||||
# Restart vsftpd to load the new certificates |
|
||||
ExecStart=systemctl --no-block restart vsftpd.service |
|
||||
# Remove the flag files after restarting vsftpd |
|
||||
ExecStartPost=/bin/sh -Eeuo pipefail -c 'rm -f /var/lib/quadlets/lego/certificates/*.renewed' |
|
||||
|
|
||||
[Install] |
|
||||
WantedBy=lego-renew.service |
|
||||
Loading…
Reference in new issue