All checks were successful
CI / skip-ci-check (pull_request) Successful in 8s
CI / lint-and-test (pull_request) Successful in 17s
CI / secret-scanning (pull_request) Successful in 8s
CI / dependency-scan (pull_request) Successful in 18s
CI / ansible-validation (pull_request) Successful in 54s
CI / sast-scan (pull_request) Successful in 29s
CI / license-check (pull_request) Successful in 14s
CI / vault-check (pull_request) Successful in 13s
CI / container-scan (pull_request) Successful in 8s
CI / sonar-analysis (pull_request) Successful in 8s
CI / playbook-test (pull_request) Successful in 27s
CI / workflow-summary (pull_request) Successful in 6s
Consolidate sprint status into handoff docs, add Listmonk/Mattermost/Mailcow and Vikunja SSO guides, Beszel alerts script, mattermost inventory, and mark phases 0–1 complete with phase 2 backlog for edge Caddy and security. Co-authored-by: Cursor <cursoragent@cursor.com>
141 lines
4.1 KiB
Bash
Executable File
141 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Configure Beszel (PocketBase) SMTP for Mailcow alerts mailbox.
|
|
#
|
|
# Prerequisite: admin account created at http://10.0.10.22:8090
|
|
#
|
|
# Usage:
|
|
# export BESZEL_URL=http://10.0.10.22:8090
|
|
# export BESZEL_EMAIL=you@example.com
|
|
# export BESZEL_PASSWORD='your-beszel-password'
|
|
# export SMTP_PASS='alerts@ mailbox password' # or source .env
|
|
# ./scripts/beszel-setup-smtp.sh
|
|
#
|
|
# Optional: SMTP_TO for test email (default idobkin@gmail.com)
|
|
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
BESZEL_URL="${BESZEL_URL:-http://10.0.10.22:8090}"
|
|
BESZEL_EMAIL="${BESZEL_EMAIL:-}"
|
|
BESZEL_PASSWORD="${BESZEL_PASSWORD:-}"
|
|
SMTP_HOST="${SMTP_HOST:-mail.levkine.ca}"
|
|
SMTP_PORT="${SMTP_PORT:-587}"
|
|
SMTP_USER="${SMTP_USER:-alerts@levkine.ca}"
|
|
SMTP_PASS="${SMTP_PASS:-}"
|
|
SMTP_TO="${SMTP_TO:-idobkin@gmail.com}"
|
|
|
|
if [[ -z "${SMTP_PASS}" ]] && [[ -f "${REPO_ROOT}/.env" ]]; then
|
|
# shellcheck disable=SC1091
|
|
set +u
|
|
set -a
|
|
# shellcheck source=/dev/null
|
|
source "${REPO_ROOT}/.env"
|
|
set +a
|
|
set -u
|
|
SMTP_PASS="${SMTP_PASS:-${ALERTS_PASSWORD:-}}"
|
|
fi
|
|
|
|
if [[ -z "${BESZEL_EMAIL}" || -z "${BESZEL_PASSWORD}" ]]; then
|
|
echo "Set BESZEL_EMAIL and BESZEL_PASSWORD (Beszel admin you just created)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "${SMTP_PASS}" ]]; then
|
|
echo "Set SMTP_PASS or ALERTS_PASSWORD (alerts@levkine.ca mailbox password)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
export BESZEL_URL BESZEL_EMAIL BESZEL_PASSWORD SMTP_HOST SMTP_PORT SMTP_USER SMTP_PASS SMTP_TO
|
|
|
|
"${REPO_ROOT}/.venv/bin/python3" <<'PY'
|
|
import json
|
|
import os
|
|
import sys
|
|
import urllib.error
|
|
import urllib.request
|
|
|
|
base = os.environ["BESZEL_URL"].rstrip("/")
|
|
email = os.environ["BESZEL_EMAIL"]
|
|
password = os.environ["BESZEL_PASSWORD"]
|
|
smtp_host = os.environ["SMTP_HOST"]
|
|
smtp_port = int(os.environ["SMTP_PORT"])
|
|
smtp_user = os.environ["SMTP_USER"]
|
|
smtp_pass = os.environ["SMTP_PASS"]
|
|
smtp_to = os.environ["SMTP_TO"]
|
|
|
|
|
|
def req(method, path, token=None, body=None):
|
|
url = f"{base}{path}"
|
|
data = None
|
|
headers = {"Content-Type": "application/json"}
|
|
if body is not None:
|
|
data = json.dumps(body).encode()
|
|
if token:
|
|
headers["Authorization"] = token
|
|
request = urllib.request.Request(url, data=data, headers=headers, method=method)
|
|
try:
|
|
with urllib.request.urlopen(request, timeout=30) as resp:
|
|
raw = resp.read().decode()
|
|
return resp.status, json.loads(raw) if raw else {}
|
|
except urllib.error.HTTPError as e:
|
|
raw = e.read().decode()
|
|
print(f"HTTP {e.code} {path}: {raw}", file=sys.stderr)
|
|
raise
|
|
|
|
|
|
print(f"Login to Beszel at {base} as {email}...")
|
|
for collection in ("_superusers", "users"):
|
|
try:
|
|
status, auth = req(
|
|
"POST",
|
|
f"/api/collections/{collection}/auth-with-password",
|
|
body={"identity": email, "password": password},
|
|
)
|
|
token = auth.get("token")
|
|
if token:
|
|
print(f"Login OK ({collection})")
|
|
break
|
|
except urllib.error.HTTPError:
|
|
token = None
|
|
continue
|
|
else:
|
|
print("Login failed: check BESZEL_EMAIL and BESZEL_PASSWORD", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
print("Configuring SMTP (Mailcow STARTTLS)...")
|
|
req(
|
|
"PATCH",
|
|
"/api/settings",
|
|
token=token,
|
|
body={
|
|
"smtp": {
|
|
"enabled": True,
|
|
"host": smtp_host,
|
|
"port": smtp_port,
|
|
"username": smtp_user,
|
|
"password": smtp_pass,
|
|
"tls": False,
|
|
"authMethod": "PLAIN",
|
|
"localName": "monitoring.levkin.ca",
|
|
},
|
|
"meta": {
|
|
"senderName": "Beszel",
|
|
"senderAddress": smtp_user,
|
|
},
|
|
},
|
|
)
|
|
print("SMTP settings saved")
|
|
|
|
print(f"Sending test email to {smtp_to}...")
|
|
req(
|
|
"POST",
|
|
"/api/settings/test/email",
|
|
token=token,
|
|
body={"email": smtp_to, "template": "verification", "collection": "_superusers"},
|
|
)
|
|
print("Test email request accepted — check inbox (and restart beszel if alerts fail later)")
|
|
|
|
print("\nDone. Restart hub to avoid cached mail client issues:")
|
|
print(" ssh root@10.0.10.22 'cd /opt/monitoring && docker compose restart beszel'")
|
|
PY
|