Initial: Caddy, Stalwart, fail2ban, crontab, allowlist scripts
This commit is contained in:
commit
4f7283ca89
|
|
@ -0,0 +1,71 @@
|
||||||
|
# Global config
|
||||||
|
{
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/access.log {
|
||||||
|
roll_size 100mb
|
||||||
|
roll_keep 5
|
||||||
|
}
|
||||||
|
format json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Zurich infrastructure
|
||||||
|
zurich.inou.com {
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-Frame-Options "SAMEORIGIN"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
Permissions-Policy "geolocation=(), microphone=(), camera=()"
|
||||||
|
-Server
|
||||||
|
}
|
||||||
|
respond "inou security infrastructure" 200
|
||||||
|
}
|
||||||
|
|
||||||
|
ntfy.inou.com {
|
||||||
|
reverse_proxy 127.0.0.1:2586
|
||||||
|
}
|
||||||
|
|
||||||
|
kuma.inou.com {
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/kuma.log {
|
||||||
|
roll_size 50mb
|
||||||
|
roll_keep 5
|
||||||
|
}
|
||||||
|
format json
|
||||||
|
}
|
||||||
|
reverse_proxy 127.0.0.1:3001
|
||||||
|
}
|
||||||
|
|
||||||
|
vault.inou.com {
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/vault.log {
|
||||||
|
roll_size 50mb
|
||||||
|
roll_keep 5
|
||||||
|
}
|
||||||
|
format json
|
||||||
|
}
|
||||||
|
reverse_proxy 127.0.0.1:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
mail.inou.com {
|
||||||
|
reverse_proxy 127.0.0.1:8880
|
||||||
|
}
|
||||||
|
|
||||||
|
mail.jongsma.me {
|
||||||
|
reverse_proxy 127.0.0.1:8880
|
||||||
|
}
|
||||||
|
|
||||||
|
harryhaasjes.nl, www.harryhaasjes.nl {
|
||||||
|
root * /var/www/harryhaasjes/public
|
||||||
|
file_server
|
||||||
|
encode gzip
|
||||||
|
}
|
||||||
|
|
||||||
|
stpetersburgaquatics.com, www.stpetersburgaquatics.com {
|
||||||
|
root * /var/www/stpetersburgaquatics/public
|
||||||
|
file_server
|
||||||
|
encode gzip
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
0 3 * * * /opt/vaultwarden/backup.sh >> /var/log/vaultwarden-backup.log 2>&1
|
||||||
|
*/15 * * * * /usr/local/bin/stalwart-allowlist-sync.sh >> /var/log/stalwart-allowsync.log 2>&1
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
[Definition]
|
||||||
|
failregex = .*"remote_ip":"<HOST>".*"uri":"/api/login.*"status":40[13]
|
||||||
|
.*"client_ip":"<HOST>".*"uri":"/api/login.*"status":40[13]
|
||||||
|
ignoreregex =
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
[Definition]
|
||||||
|
failregex = .*"remote_ip":"<HOST>".*"uri":".*(?:wp-admin|wp-login|\.env|\.git|phpmyadmin|phpinfo|xmlrpc|actuator|setup\.php|config\.php|admin\.php|shell|eval\(|\.aws|\.ssh).*"status":(?:400|403|404|405)
|
||||||
|
.*"client_ip":"<HOST>".*"uri":".*(?:wp-admin|wp-login|\.env|\.git|phpmyadmin|phpinfo|xmlrpc|actuator|setup\.php|config\.php|admin\.php|shell|eval\(|\.aws|\.ssh).*"status":(?:400|403|404|405)
|
||||||
|
ignoreregex =
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
[DEFAULT]
|
||||||
|
banaction = nftables
|
||||||
|
banaction_allports = nftables[type=allports]
|
||||||
|
backend = systemd
|
||||||
|
|
||||||
|
[sshd]
|
||||||
|
enabled = true
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
[sshd]
|
||||||
|
enabled = true
|
||||||
|
port = ssh
|
||||||
|
filter = sshd
|
||||||
|
logpath = /var/log/auth.log
|
||||||
|
maxretry = 3
|
||||||
|
bantime = 3600
|
||||||
|
findtime = 600
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
[Definition]
|
||||||
|
# Match auth failures and too-many-attempts from Stalwart logs
|
||||||
|
failregex = ^\S+ \S+ .*\(auth\.failed\).*remoteIp = <HOST>
|
||||||
|
^\S+ \S+ .*\(auth\.too-many-attempts\).*remoteIp = <HOST>
|
||||||
|
ignoreregex =
|
||||||
|
datepattern = %%Y-%%m-%%dT%%H:%%M:%%SZ
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
[Definition]
|
||||||
|
failregex = .*"remote_ip":"<HOST>".*"uri":"/api/accounts/login.*"status":40[13]
|
||||||
|
.*"client_ip":"<HOST>".*"uri":"/api/accounts/login.*"status":40[13]
|
||||||
|
ignoreregex =
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
STATE_FILE=/var/lib/stalwart-allowsync/home-ip
|
||||||
|
CURRENT_IP=47.197.93.62
|
||||||
|
[ -z "$CURRENT_IP" ] && exit 1
|
||||||
|
mkdir -p /var/lib/stalwart-allowsync
|
||||||
|
LAST_IP=$(cat "$STATE_FILE" 2>/dev/null)
|
||||||
|
[ "$CURRENT_IP" = "$LAST_IP" ] && exit 0
|
||||||
|
echo "$(date -u): Home IP changed: $LAST_IP -> $CURRENT_IP"
|
||||||
|
python3 /usr/local/bin/stalwart-update-allowip.py "$CURRENT_IP"
|
||||||
|
/opt/stalwart/bin/stalwart-cli -u http://127.0.0.1:8880 -c admin:JamesAdmin2026x server reload-config > /dev/null
|
||||||
|
echo "$CURRENT_IP" > "$STATE_FILE"
|
||||||
|
echo Done.
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import sys, re
|
||||||
|
new_ip = sys.argv[1]
|
||||||
|
config_path = '/opt/stalwart/etc/config.toml'
|
||||||
|
content = open(config_path).read()
|
||||||
|
new_section = '[server.allowed-ip]\n"' + new_ip + '" = true\n'
|
||||||
|
if '[server.allowed-ip]' in content:
|
||||||
|
content = re.sub(r'\[server\.allowed-ip\].*?(?=\n\[|\Z)', new_section, content, flags=re.DOTALL)
|
||||||
|
else:
|
||||||
|
content = content.rstrip() + '\n\n' + new_section
|
||||||
|
open(config_path, 'w').write(content)
|
||||||
|
print(f'Updated allowed-ip to {new_ip}')
|
||||||
|
|
||||||
|
# After writing config, commit to git
|
||||||
|
import subprocess
|
||||||
|
subprocess.run(['git', '-C', '/opt/stalwart/etc', 'add', 'config.toml'], capture_output=True)
|
||||||
|
subprocess.run(['git', '-C', '/opt/stalwart/etc', 'commit', '-m', f'auto: allowed-ip updated to {new_ip}'], capture_output=True)
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
[server.listener.smtp]
|
||||||
|
bind = "[::]:25"
|
||||||
|
protocol = "smtp"
|
||||||
|
|
||||||
|
[server.listener.submission]
|
||||||
|
bind = "[::]:587"
|
||||||
|
protocol = "smtp"
|
||||||
|
|
||||||
|
[server.listener.submissions]
|
||||||
|
bind = "[::]:465"
|
||||||
|
protocol = "smtp"
|
||||||
|
tls.implicit = true
|
||||||
|
|
||||||
|
[server.listener.imap]
|
||||||
|
bind = "[::]:143"
|
||||||
|
protocol = "imap"
|
||||||
|
|
||||||
|
[server.listener.imaptls]
|
||||||
|
bind = "[::]:993"
|
||||||
|
protocol = "imap"
|
||||||
|
tls.implicit = true
|
||||||
|
|
||||||
|
[server.listener.pop3]
|
||||||
|
bind = "[::]:110"
|
||||||
|
protocol = "pop3"
|
||||||
|
|
||||||
|
[server.listener.pop3s]
|
||||||
|
bind = "[::]:995"
|
||||||
|
protocol = "pop3"
|
||||||
|
tls.implicit = true
|
||||||
|
|
||||||
|
[server.listener.sieve]
|
||||||
|
bind = "[::]:4190"
|
||||||
|
protocol = "managesieve"
|
||||||
|
|
||||||
|
[server.listener.https]
|
||||||
|
protocol = "http"
|
||||||
|
bind = "127.0.0.1:8443"
|
||||||
|
tls.implicit = false
|
||||||
|
|
||||||
|
[server.listener.http]
|
||||||
|
protocol = "http"
|
||||||
|
bind = "127.0.0.1:8880"
|
||||||
|
|
||||||
|
[storage]
|
||||||
|
data = "rocksdb"
|
||||||
|
fts = "rocksdb"
|
||||||
|
blob = "rocksdb"
|
||||||
|
lookup = "rocksdb"
|
||||||
|
directory = "internal"
|
||||||
|
|
||||||
|
[store.rocksdb]
|
||||||
|
type = "rocksdb"
|
||||||
|
path = "/opt/stalwart/data"
|
||||||
|
compression = "lz4"
|
||||||
|
|
||||||
|
[directory.internal]
|
||||||
|
type = "internal"
|
||||||
|
store = "rocksdb"
|
||||||
|
|
||||||
|
[tracer.log]
|
||||||
|
type = "log"
|
||||||
|
level = "info"
|
||||||
|
path = "/opt/stalwart/logs"
|
||||||
|
prefix = "stalwart.log"
|
||||||
|
rotate = "daily"
|
||||||
|
ansi = false
|
||||||
|
enable = true
|
||||||
|
|
||||||
|
[authentication.fallback-admin]
|
||||||
|
user = "admin"
|
||||||
|
secret = "$6$stalwartjames$OlCxhWXHNuO3Szh.HHPmjuh3oI/B0iCYjeERKqXSlpGHw40oHxVOd0IW9pJZn54QjA2Dbdlrin.SQRfZBG8pw1"
|
||||||
|
|
||||||
|
[lookup.default]
|
||||||
|
hostname = "mail.jongsma.me"
|
||||||
|
|
||||||
|
[certificate.default]
|
||||||
|
cert = "%{file:/etc/letsencrypt/live/mail.jongsma.me/fullchain.pem}%"
|
||||||
|
private-key = "%{file:/etc/letsencrypt/live/mail.jongsma.me/privkey.pem}%"
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[server.allowed-ip]
|
||||||
|
"47.197.93.62" = true
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Vaultwarden daily backup
|
||||||
|
BACKUP_DIR="/opt/vaultwarden/backups"
|
||||||
|
DATA_DIR="/opt/vaultwarden/data"
|
||||||
|
DATE=$(date +%Y-%m-%d)
|
||||||
|
BACKUP_FILE="$BACKUP_DIR/vaultwarden-$DATE.tar.gz.gpg"
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
# Stop container briefly for consistent backup
|
||||||
|
docker stop vaultwarden
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Create encrypted backup (symmetric, passphrase from file)
|
||||||
|
tar czf - -C /opt/vaultwarden data | gpg --batch --yes --symmetric --cipher-algo AES256 --passphrase-file /opt/vaultwarden/.backup_passphrase -o "$BACKUP_FILE"
|
||||||
|
|
||||||
|
# Restart
|
||||||
|
docker start vaultwarden
|
||||||
|
|
||||||
|
# Upload to gdrive if rclone is configured
|
||||||
|
if rclone listremotes 2>/dev/null | grep -q gdrive; then
|
||||||
|
rclone copy "$BACKUP_FILE" gdrive:backups/vaultwarden/
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Retain only last 30 days
|
||||||
|
find "$BACKUP_DIR" -name "vaultwarden-*.tar.gz.gpg" -mtime +30 -delete
|
||||||
|
|
||||||
|
echo "Backup complete: $BACKUP_FILE ($(du -h "$BACKUP_FILE" | cut -f1))"
|
||||||
Loading…
Reference in New Issue