Compare commits
5 Commits
7d6085b3cc
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7721756d1f | |||
| bf62af7438 | |||
| 6b076b9585 | |||
| 3d05e69557 | |||
| a8b47c33d9 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,8 +1,12 @@
|
|||||||
data
|
data
|
||||||
dkim
|
./dkim
|
||||||
filter
|
filter
|
||||||
mail
|
mail
|
||||||
mailqueue
|
mailqueue
|
||||||
overrides
|
overrides
|
||||||
redis
|
redis
|
||||||
mailu.env
|
mailu.env
|
||||||
|
.env
|
||||||
|
private
|
||||||
|
private/
|
||||||
|
*.bak
|
||||||
|
|||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Tord-Vincent Heggland
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -5,11 +5,11 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: mailu.env
|
env_file: mailu.env
|
||||||
ports:
|
ports:
|
||||||
- "25:25"
|
- "2525:25"
|
||||||
- "587:587"
|
- "2465:465"
|
||||||
- "993:993"
|
- "2993:993"
|
||||||
volumes:
|
volumes:
|
||||||
- ./certs:/certs
|
- ${CADDY_MAIL_CERT_DIR}:/certs:ro
|
||||||
- ./overrides/nginx:/overrides:ro
|
- ./overrides/nginx:/overrides:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- resolver
|
- resolver
|
||||||
@@ -34,7 +34,7 @@ services:
|
|||||||
container_name: mailu-redis
|
container_name: mailu-redis
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ./redis:/data
|
- mailu_redis:/data
|
||||||
networks:
|
networks:
|
||||||
mailu_net:
|
mailu_net:
|
||||||
ipv4_address: 192.168.203.3
|
ipv4_address: 192.168.203.3
|
||||||
@@ -45,8 +45,8 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: mailu.env
|
env_file: mailu.env
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/data
|
- mailu_data:/data
|
||||||
- ./dkim:/dkim
|
- mailu_dkim:/dkim
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- resolver
|
- resolver
|
||||||
@@ -62,7 +62,7 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: mailu.env
|
env_file: mailu.env
|
||||||
volumes:
|
volumes:
|
||||||
- ./mail:/mail
|
- mailu_mail:/mail
|
||||||
- ./overrides/dovecot:/overrides:ro
|
- ./overrides/dovecot:/overrides:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- resolver
|
- resolver
|
||||||
@@ -78,7 +78,7 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: mailu.env
|
env_file: mailu.env
|
||||||
volumes:
|
volumes:
|
||||||
- ./mailqueue:/queue
|
- mailu_mailqueue:/queue
|
||||||
- ./overrides/postfix:/overrides:ro
|
- ./overrides/postfix:/overrides:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- resolver
|
- resolver
|
||||||
@@ -94,39 +94,40 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: mailu.env
|
env_file: mailu.env
|
||||||
volumes:
|
volumes:
|
||||||
- ./filter:/var/lib/rspamd
|
- mailu_filter:/var/lib/rspamd
|
||||||
- ./dkim:/dkim
|
- mailu_dkim:/dkim
|
||||||
- ./overrides/rspamd:/overrides:ro
|
- ./overrides/rspamd:/overrides:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- resolver
|
- resolver
|
||||||
# - clamav
|
- antivirus
|
||||||
dns:
|
dns:
|
||||||
- 192.168.203.254
|
- 192.168.203.254
|
||||||
networks:
|
networks:
|
||||||
mailu_net:
|
mailu_net:
|
||||||
ipv4_address: 192.168.203.7
|
ipv4_address: 192.168.203.7
|
||||||
|
|
||||||
# clamav:
|
antivirus:
|
||||||
# image: ghcr.io/mailu/clamav:2024.06
|
image: clamav/clamav-debian:1.4_base
|
||||||
# container_name: mailu-clamav
|
container_name: mailu-antivirus
|
||||||
# restart: unless-stopped
|
restart: unless-stopped
|
||||||
# env_file: mailu.env
|
volumes:
|
||||||
# volumes:
|
- mailu_clamav:/var/lib/clamav
|
||||||
# - ./filter/clamav:/data
|
networks:
|
||||||
# networks:
|
mailu_net:
|
||||||
# mailu_net:
|
ipv4_address: 192.168.203.8
|
||||||
# ipv4_address: 192.168.203.8
|
|
||||||
|
|
||||||
webmail:
|
webmail:
|
||||||
image: ghcr.io/mailu/roundcube:2024.06
|
image: ghcr.io/mailu/webmail:2024.06
|
||||||
container_name: mailu-webmail
|
container_name: mailu-webmail
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: mailu.env
|
env_file: mailu.env
|
||||||
volumes:
|
volumes:
|
||||||
- ./webmail:/data
|
- mailu_webmail:/data
|
||||||
depends_on:
|
depends_on:
|
||||||
- imap
|
- imap
|
||||||
- smtp
|
- smtp
|
||||||
|
dns:
|
||||||
|
- 192.168.203.254
|
||||||
networks:
|
networks:
|
||||||
mailu_net:
|
mailu_net:
|
||||||
ipv4_address: 192.168.203.9
|
ipv4_address: 192.168.203.9
|
||||||
@@ -140,3 +141,13 @@ networks:
|
|||||||
|
|
||||||
proxy_net:
|
proxy_net:
|
||||||
external: true
|
external: true
|
||||||
|
volumes:
|
||||||
|
# mailu_certs:
|
||||||
|
mailu_data:
|
||||||
|
mailu_dkim:
|
||||||
|
mailu_filter:
|
||||||
|
mailu_mail:
|
||||||
|
mailu_mailqueue:
|
||||||
|
mailu_redis:
|
||||||
|
mailu_webmail:
|
||||||
|
mailu_clamav:
|
||||||
|
|||||||
62
script/dkim/01-generate-keys.sh
Executable file
62
script/dkim/01-generate-keys.sh
Executable file
@@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
# Prosess 1:
|
||||||
|
# Genererer DKIM private/public key-filer for ett eller flere domener.
|
||||||
|
#
|
||||||
|
# Filer lages under:
|
||||||
|
# private/dkim/<domene>.<selector>.private.pem
|
||||||
|
# private/dkim/<domene>.<selector>.public.pem
|
||||||
|
#
|
||||||
|
# Dette scriptet er trygt å publisere.
|
||||||
|
# Selve nøklene ligger i private/, som skal være i .gitignore.
|
||||||
|
|
||||||
|
selector="${DKIM_SELECTOR:-mail}"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Bruk:
|
||||||
|
$0 <domene> [domene...]
|
||||||
|
|
||||||
|
Eksempel:
|
||||||
|
$0 tvheggland.no privix.no
|
||||||
|
|
||||||
|
Valgfritt:
|
||||||
|
DKIM_SELECTOR=mail $0 tvheggland.no
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p private/dkim
|
||||||
|
chmod 700 private private/dkim
|
||||||
|
|
||||||
|
for domain in "$@"; do
|
||||||
|
private_key="private/dkim/${domain}.${selector}.private.pem"
|
||||||
|
public_key="private/dkim/${domain}.${selector}.public.pem"
|
||||||
|
|
||||||
|
if [[ -e "$private_key" || -e "$public_key" ]]; then
|
||||||
|
echo "SKIP: DKIM-filer finnes allerede for ${domain}"
|
||||||
|
echo " $private_key"
|
||||||
|
echo " $public_key"
|
||||||
|
echo
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
openssl genrsa -out "$private_key" 2048
|
||||||
|
|
||||||
|
openssl rsa \
|
||||||
|
-in "$private_key" \
|
||||||
|
-pubout \
|
||||||
|
-out "$public_key" >/dev/null 2>&1
|
||||||
|
|
||||||
|
chmod 600 "$private_key" "$public_key"
|
||||||
|
|
||||||
|
echo "OK: Genererte DKIM-nøkler for ${domain}"
|
||||||
|
echo " Privat nøkkel: $private_key"
|
||||||
|
echo " Offentlig nøkkel: $public_key"
|
||||||
|
echo
|
||||||
|
done
|
||||||
91
script/dkim/02-import-to-mailu.sh
Executable file
91
script/dkim/02-import-to-mailu.sh
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
# Prosess 2:
|
||||||
|
# Importerer alle private DKIM-nøkler fra private/dkim/ til Mailu.
|
||||||
|
#
|
||||||
|
# Leser:
|
||||||
|
# private/dkim/<domene>.<selector>.private.pem
|
||||||
|
#
|
||||||
|
# Skriver:
|
||||||
|
# private/mailu-dkim-import.yml
|
||||||
|
#
|
||||||
|
# Dette scriptet er trygt å publisere.
|
||||||
|
# Importfilen og private nøkler ligger under private/, som skal være i .gitignore.
|
||||||
|
|
||||||
|
selector="${DKIM_SELECTOR:-mail}"
|
||||||
|
import_file="private/mailu-dkim-import.yml"
|
||||||
|
|
||||||
|
mapfile -t private_keys < <(
|
||||||
|
find private/dkim -maxdepth 1 -type f -name "*.${selector}.private.pem" | sort
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ ${#private_keys[@]} -eq 0 ]]; then
|
||||||
|
echo "FEIL: Fant ingen private DKIM-nøkler."
|
||||||
|
echo "Forventet filer som:"
|
||||||
|
echo " private/dkim/<domene>.${selector}.private.pem"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "domain:"
|
||||||
|
for private_key in "${private_keys[@]}"; do
|
||||||
|
filename="$(basename "$private_key")"
|
||||||
|
domain="${filename%.${selector}.private.pem}"
|
||||||
|
|
||||||
|
echo " - name: ${domain}"
|
||||||
|
echo " dkim_key: |"
|
||||||
|
sed 's/^/ /' "$private_key"
|
||||||
|
done
|
||||||
|
} > "$import_file"
|
||||||
|
|
||||||
|
chmod 600 "$import_file"
|
||||||
|
|
||||||
|
echo "Importfil laget:"
|
||||||
|
echo " $import_file"
|
||||||
|
echo
|
||||||
|
echo "Domener som blir importert:"
|
||||||
|
for private_key in "${private_keys[@]}"; do
|
||||||
|
filename="$(basename "$private_key")"
|
||||||
|
domain="${filename%.${selector}.private.pem}"
|
||||||
|
echo " - $domain"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Dry-run mot Mailu:"
|
||||||
|
docker compose exec -T admin flask mailu config-import \
|
||||||
|
--update \
|
||||||
|
--dry-run \
|
||||||
|
--verbose \
|
||||||
|
- < "$import_file"
|
||||||
|
|
||||||
|
echo
|
||||||
|
read -r -p "Importere DKIM-nøklene i Mailu nå? Skriv YES: " confirm
|
||||||
|
|
||||||
|
if [[ "$confirm" != "YES" ]]; then
|
||||||
|
echo "Avbrutt. Ingen endring gjort."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker compose exec -T admin flask mailu config-import \
|
||||||
|
--update \
|
||||||
|
--verbose \
|
||||||
|
- < "$import_file"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "DKIM-status i Mailu:"
|
||||||
|
docker compose exec -T admin flask mailu config-export domain \
|
||||||
|
| grep -A5 -E 'name:|dkim_key'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Restarter relevante Mailu-tjenester hvis de finnes..."
|
||||||
|
services="$(docker compose ps --services)"
|
||||||
|
|
||||||
|
for svc in admin smtp antispam; do
|
||||||
|
if echo "$services" | grep -qx "$svc"; then
|
||||||
|
docker compose restart "$svc"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "OK: DKIM-nøkler importert til Mailu."
|
||||||
69
script/dkim/03-print-domeneshop-records.sh
Executable file
69
script/dkim/03-print-domeneshop-records.sh
Executable file
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
# Prosess 3:
|
||||||
|
# Skriver ut DNS TXT-recordene som skal legges inn i Domeneshop.
|
||||||
|
#
|
||||||
|
# Leser:
|
||||||
|
# private/dkim/<domene>.<selector>.public.pem
|
||||||
|
#
|
||||||
|
# Skriver:
|
||||||
|
# private/dkim-domeneshop-records.txt
|
||||||
|
#
|
||||||
|
# Dette scriptet printer bare PUBLIC key. Det er ikke privatnøkkelen.
|
||||||
|
# Likevel lagres output under private/ for å holde repoet ryddig.
|
||||||
|
|
||||||
|
selector="${DKIM_SELECTOR:-mail}"
|
||||||
|
output_file="private/dkim-domeneshop-records.txt"
|
||||||
|
|
||||||
|
mapfile -t public_keys < <(
|
||||||
|
find private/dkim -maxdepth 1 -type f -name "*.${selector}.public.pem" | sort
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ ${#public_keys[@]} -eq 0 ]]; then
|
||||||
|
echo "FEIL: Fant ingen offentlige DKIM-nøkler."
|
||||||
|
echo "Forventet filer som:"
|
||||||
|
echo " private/dkim/<domene>.${selector}.public.pem"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
{
|
||||||
|
for public_key in "${public_keys[@]}"; do
|
||||||
|
filename="$(basename "$public_key")"
|
||||||
|
domain="${filename%.${selector}.public.pem}"
|
||||||
|
pubkey="$(grep -v -- '-----' "$public_key" | tr -d '\n\r ')"
|
||||||
|
|
||||||
|
if [[ -z "$pubkey" ]]; then
|
||||||
|
echo "FEIL: Public key ble tom for ${domain}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "============================================================"
|
||||||
|
echo "DKIM for ${domain}"
|
||||||
|
echo "============================================================"
|
||||||
|
echo
|
||||||
|
echo "I Domeneshop:"
|
||||||
|
echo
|
||||||
|
echo "Vertsnavn / hostname:"
|
||||||
|
echo "${selector}._domainkey"
|
||||||
|
echo
|
||||||
|
echo "Type:"
|
||||||
|
echo "TXT"
|
||||||
|
echo
|
||||||
|
echo "Verdi / parameter:"
|
||||||
|
echo "v=DKIM1; k=rsa; p=${pubkey}"
|
||||||
|
echo
|
||||||
|
echo "Fullt DNS-navn:"
|
||||||
|
echo "${selector}._domainkey.${domain}"
|
||||||
|
echo
|
||||||
|
echo "Test etter lagring:"
|
||||||
|
echo "dig TXT ${selector}._domainkey.${domain} +short"
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
} | tee "$output_file"
|
||||||
|
|
||||||
|
chmod 600 "$output_file"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Kopi lagret her:"
|
||||||
|
echo " $output_file"
|
||||||
Reference in New Issue
Block a user