This commit is contained in:
2026-10-03 16:49:49 +07:00
parent 55179c9508
commit 17f551aa46
7 changed files with 98 additions and 7 deletions
+20 -1
View File
@@ -1,4 +1,23 @@
# mail server # Mail server
## Запуск
```bash
./up.sh
```
Скрипт поднимет почтовый контейнер, запросит пароли для адресов из
`accounts.txt`, создаст DKIM и проверит TLS. Пароли не сохраняются в файлы.
## Удаление старого сервера
Удаляет контейнер и все почтовые volumes без возможности восстановления:
```bash
DELETE_MAIL_DATA=YES ./destroy.sh
```
`reproxy` и игровые контейнеры скрипт не трогает.
Папки: Папки:
+2
View File
@@ -0,0 +1,2 @@
evening_detective@crabs-games.art
admin@crabs-games.art
Executable
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
DOMAIN="${MAIL_DOMAIN:-mail.crabs-games.art}"
docker ps --filter name=^/mailserver$ --format 'mailserver: {{.Status}}'
openssl s_client \
-connect "$DOMAIN:465" \
-servername "$DOMAIN" </dev/null 2>/dev/null |
openssl x509 -noout -subject -issuer -dates
Executable
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml"
if [ "${DELETE_MAIL_DATA:-}" != "YES" ]; then
echo "This removes the mailserver container and all mail volumes." >&2
echo "Run: DELETE_MAIL_DATA=YES ./destroy.sh" >&2
exit 1
fi
docker compose -f "$COMPOSE_FILE" down --remove-orphans
docker volume rm \
email_server_mail-data \
email_server_mail-state \
email_server_mail-logs 2>/dev/null || true
echo "Old mail server and mail data removed."
+2 -3
View File
@@ -1,6 +1,6 @@
services: services:
mailserver: mailserver:
image: mailserver/docker-mailserver:latest image: mailserver/docker-mailserver:v15.1.0
container_name: mailserver container_name: mailserver
hostname: mail.crabs-games.art hostname: mail.crabs-games.art
ports: ports:
@@ -25,7 +25,7 @@ services:
- mail-data:/var/mail - mail-data:/var/mail
- mail-state:/var/mail-state - mail-state:/var/mail-state
- mail-logs:/var/log/mail - mail-logs:/var/log/mail
- /Users/vladimir/reproxy/var/ssl/certificates/acme-v02.api.letsencrypt.org-directory/mail.crabs-games.art:/etc/letsencrypt - ${REPROXY_SSL_DIR:-/Users/vladimir/reproxy/var/ssl}/certificates/acme-v02.api.letsencrypt.org-directory/mail.crabs-games.art:/etc/letsencrypt
restart: always restart: always
networks: networks:
- crabs-network - crabs-network
@@ -39,4 +39,3 @@ volumes:
mail-data: mail-data:
mail-state: mail-state:
mail-logs: mail-logs:
+9 -3
View File
@@ -5,13 +5,15 @@ DOMAIN="${MAIL_DOMAIN:-mail.crabs-games.art}"
EMAIL="${ACME_EMAIL:-admin@crabs-games.art}" EMAIL="${ACME_EMAIL:-admin@crabs-games.art}"
REPROXY_CONTAINER="${REPROXY_CONTAINER:-reproxy}" REPROXY_CONTAINER="${REPROXY_CONTAINER:-reproxy}"
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
SSL_DIR="$SCRIPT_DIR/ssl" REPROXY_SSL_DIR="${REPROXY_SSL_DIR:-/Users/vladimir/reproxy/var/ssl}"
CERTBOT_DIR="$REPROXY_SSL_DIR/certbot"
CERT_DIR="$REPROXY_SSL_DIR/certificates/acme-v02.api.letsencrypt.org-directory/$DOMAIN"
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml" COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml"
command -v docker >/dev/null || { echo "docker is required" >&2; exit 1; } command -v docker >/dev/null || { echo "docker is required" >&2; exit 1; }
docker info >/dev/null || { echo "docker access is required" >&2; exit 1; } docker info >/dev/null || { echo "docker access is required" >&2; exit 1; }
mkdir -p "$SSL_DIR" mkdir -p "$CERTBOT_DIR" "$CERT_DIR"
reproxy_was_running=0 reproxy_was_running=0
if docker inspect -f '{{.State.Running}}' "$REPROXY_CONTAINER" 2>/dev/null | grep -qx true; then if docker inspect -f '{{.State.Running}}' "$REPROXY_CONTAINER" 2>/dev/null | grep -qx true; then
@@ -28,15 +30,19 @@ trap restart_reproxy EXIT
docker run --rm \ docker run --rm \
-p 80:80 \ -p 80:80 \
-v "$SSL_DIR:/etc/letsencrypt" \ -v "$CERTBOT_DIR:/etc/letsencrypt" \
certbot/certbot:latest \ certbot/certbot:latest \
certonly --standalone \ certonly --standalone \
--keep-until-expiring \ --keep-until-expiring \
--non-interactive \ --non-interactive \
--agree-tos \ --agree-tos \
--email "$EMAIL" \ --email "$EMAIL" \
--cert-name "$DOMAIN" \
-d "$DOMAIN" -d "$DOMAIN"
cp "$CERTBOT_DIR/live/$DOMAIN/fullchain.pem" "$CERT_DIR/$DOMAIN.crt"
cp "$CERTBOT_DIR/live/$DOMAIN/privkey.pem" "$CERT_DIR/$DOMAIN.key"
docker compose -f "$COMPOSE_FILE" up -d --force-recreate mailserver docker compose -f "$COMPOSE_FILE" up -d --force-recreate mailserver
echo "TLS certificate for $DOMAIN is installed." echo "TLS certificate for $DOMAIN is installed."
Executable
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml"
ACCOUNTS_FILE="${ACCOUNTS_FILE:-$SCRIPT_DIR/accounts.txt}"
export REPROXY_SSL_DIR="${REPROXY_SSL_DIR:-/Users/vladimir/reproxy/var/ssl}"
command -v docker >/dev/null || { echo "docker is required" >&2; exit 1; }
docker info >/dev/null || { echo "docker access is required" >&2; exit 1; }
docker network inspect crabs-network >/dev/null 2>&1 || docker network create crabs-network >/dev/null
CERT="$REPROXY_SSL_DIR/certificates/acme-v02.api.letsencrypt.org-directory/mail.crabs-games.art/mail.crabs-games.art.crt"
if [ ! -f "$CERT" ] || ! openssl x509 -in "$CERT" -noout -checkend 2592000 >/dev/null 2>&1; then
"$SCRIPT_DIR/setup-mail-tls.sh"
fi
docker compose -f "$COMPOSE_FILE" up -d mailserver
while IFS= read -r account || [ -n "$account" ]; do
[[ -z "$account" || "$account" == \#* ]] && continue
if docker exec mailserver setup email list 2>/dev/null | grep -Fq "$account"; then
echo "exists: $account"
continue
fi
read -r -s -p "Password for $account: " password
echo
[ -n "$password" ] || { echo "empty password is not allowed" >&2; exit 1; }
docker exec mailserver setup email add "$account" "$password"
unset password
done < "$ACCOUNTS_FILE"
docker exec mailserver setup config dkim
echo "Mail server is running."
"$SCRIPT_DIR/check.sh"