Merge pull request #18 from outis1one/claude/fix-magic-mirror-setup-LWG3r
Fix Magic Mirror npm setup and add ActualBudget, Keycloak, Caddy/fail…
This commit is contained in:
@@ -0,0 +1,371 @@
|
|||||||
|
# Caddy with Fail2ban Setup Guide
|
||||||
|
|
||||||
|
This guide helps you integrate new services with an existing Caddy reverse proxy and set up fail2ban protection.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
For servers with Caddy already installed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run the automated helper script
|
||||||
|
./caddy-setup-helper.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This script will:
|
||||||
|
- ✅ Detect your Caddy installation
|
||||||
|
- ✅ Locate and backup your Caddyfile
|
||||||
|
- ✅ Check for fail2ban configuration
|
||||||
|
- ✅ Provide examples for adding new services
|
||||||
|
|
||||||
|
## Manual Setup
|
||||||
|
|
||||||
|
### 1. Backup Your Caddyfile
|
||||||
|
|
||||||
|
**IMPORTANT:** Always backup before making changes!
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find your Caddyfile location
|
||||||
|
CADDYFILE=~/docker/caddy/Caddyfile # Adjust path as needed
|
||||||
|
|
||||||
|
# Create backup directory
|
||||||
|
mkdir -p $(dirname "$CADDYFILE")/backups
|
||||||
|
|
||||||
|
# Backup with timestamp
|
||||||
|
cp "$CADDYFILE" "$(dirname "$CADDYFILE")/backups/Caddyfile.backup.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Add New Services to Caddy
|
||||||
|
|
||||||
|
Add these blocks to your Caddyfile:
|
||||||
|
|
||||||
|
#### ActualBudget (Personal Finance)
|
||||||
|
|
||||||
|
```caddy
|
||||||
|
budget.yourdomain.com {
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/actualbudget-access.log
|
||||||
|
format json
|
||||||
|
level INFO
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse_proxy localhost:5006
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||||
|
X-Frame-Options "SAMEORIGIN"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-XSS-Protection "1; mode=block"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Keycloak (Identity & Access Management)
|
||||||
|
|
||||||
|
```caddy
|
||||||
|
auth.yourdomain.com {
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/keycloak-access.log
|
||||||
|
format json
|
||||||
|
level INFO
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse_proxy localhost:8180
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||||
|
X-Frame-Options "SAMEORIGIN"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-XSS-Protection "1; mode=block"
|
||||||
|
Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Reload Caddy Configuration
|
||||||
|
|
||||||
|
After editing the Caddyfile:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Format the Caddyfile (optional but recommended)
|
||||||
|
docker exec -w /etc/caddy caddy caddy fmt --overwrite
|
||||||
|
|
||||||
|
# Reload Caddy configuration
|
||||||
|
docker exec -w /etc/caddy caddy caddy reload
|
||||||
|
```
|
||||||
|
|
||||||
|
If you get errors, check Caddy logs:
|
||||||
|
```bash
|
||||||
|
docker logs caddy
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Restore from Backup (if needed)
|
||||||
|
|
||||||
|
If something goes wrong:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find your backup
|
||||||
|
ls -lah ~/docker/caddy/backups/
|
||||||
|
|
||||||
|
# Restore the backup
|
||||||
|
cp ~/docker/caddy/backups/Caddyfile.backup.YYYYMMDD_HHMMSS ~/docker/caddy/Caddyfile
|
||||||
|
|
||||||
|
# Reload Caddy
|
||||||
|
docker exec -w /etc/caddy caddy caddy reload
|
||||||
|
docker exec -w /etc/caddy caddy caddy fmt --overwrite
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fail2ban Configuration
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
1. **Enable JSON logging in Caddy** (shown in examples above)
|
||||||
|
2. **Install fail2ban** on the host:
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install fail2ban -y
|
||||||
|
```
|
||||||
|
|
||||||
|
### Installation Steps
|
||||||
|
|
||||||
|
#### Step 1: Install Fail2ban Filter
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy the filter configuration
|
||||||
|
sudo cp fail2ban-caddy-filter.conf /etc/fail2ban/filter.d/caddy-auth.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
Or create it manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo tee /etc/fail2ban/filter.d/caddy-auth.conf > /dev/null <<'EOF'
|
||||||
|
[Definition]
|
||||||
|
failregex = ^.*"remote_ip":"<HOST>".*"status":(?:401|403|429).*$
|
||||||
|
^.*"remote_addr":"<HOST>.*"status":(?:401|403|429).*$
|
||||||
|
ignoreregex = ^.*"remote_ip":"(?:127\.0\.0\.1|::1)".*$
|
||||||
|
datepattern = "ts":%%s
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 2: Install Fail2ban Jail
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy the jail configuration
|
||||||
|
sudo cp fail2ban-caddy-jail.conf /etc/fail2ban/jail.d/caddy.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
Or create it manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo tee /etc/fail2ban/jail.d/caddy.conf > /dev/null <<'EOF'
|
||||||
|
[caddy-auth]
|
||||||
|
enabled = true
|
||||||
|
port = http,https
|
||||||
|
filter = caddy-auth
|
||||||
|
logpath = /var/log/caddy/access.log
|
||||||
|
/var/log/caddy/*-access.log
|
||||||
|
maxretry = 5
|
||||||
|
findtime = 600
|
||||||
|
bantime = 3600
|
||||||
|
action = iptables-multiport[name=CaddyAuth, port="http,https", protocol=tcp]
|
||||||
|
backend = auto
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 3: Create Log Directory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create log directory if using Docker Caddy
|
||||||
|
sudo mkdir -p /var/log/caddy
|
||||||
|
sudo chmod 755 /var/log/caddy
|
||||||
|
|
||||||
|
# If Caddy runs as specific user:
|
||||||
|
# sudo chown caddy:caddy /var/log/caddy
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 4: Update Caddy Docker Compose
|
||||||
|
|
||||||
|
Add log volume to your Caddy docker-compose.yml:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
caddy:
|
||||||
|
image: caddy:latest
|
||||||
|
container_name: caddy
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./Caddyfile:/etc/caddy/Caddyfile
|
||||||
|
- ./data:/data
|
||||||
|
- ./config:/config
|
||||||
|
- /var/log/caddy:/var/log/caddy # Add this line
|
||||||
|
```
|
||||||
|
|
||||||
|
Then restart Caddy:
|
||||||
|
```bash
|
||||||
|
cd ~/docker/caddy
|
||||||
|
docker compose down
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 5: Restart Fail2ban
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl restart fail2ban
|
||||||
|
sudo systemctl status fail2ban
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Fail2ban
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check if jail is running
|
||||||
|
sudo fail2ban-client status caddy-auth
|
||||||
|
|
||||||
|
# Test the filter against your logs
|
||||||
|
sudo fail2ban-regex /var/log/caddy/access.log /etc/fail2ban/filter.d/caddy-auth.conf
|
||||||
|
|
||||||
|
# View banned IPs
|
||||||
|
sudo fail2ban-client get caddy-auth banip
|
||||||
|
|
||||||
|
# Manually ban/unban an IP (for testing)
|
||||||
|
sudo fail2ban-client set caddy-auth banip 1.2.3.4
|
||||||
|
sudo fail2ban-client set caddy-auth unbanip 1.2.3.4
|
||||||
|
```
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
#### Fail2ban not detecting attacks
|
||||||
|
|
||||||
|
1. **Check log format:**
|
||||||
|
```bash
|
||||||
|
tail -f /var/log/caddy/access.log
|
||||||
|
```
|
||||||
|
Ensure it's JSON format with `remote_ip` or `remote_addr` field.
|
||||||
|
|
||||||
|
2. **Test filter manually:**
|
||||||
|
```bash
|
||||||
|
sudo fail2ban-regex /var/log/caddy/access.log /etc/fail2ban/filter.d/caddy-auth.conf --print-all-matched
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Check fail2ban logs:**
|
||||||
|
```bash
|
||||||
|
sudo tail -f /var/log/fail2ban.log
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Caddy configuration errors
|
||||||
|
|
||||||
|
1. **Validate Caddyfile:**
|
||||||
|
```bash
|
||||||
|
docker exec caddy caddy validate --config /etc/caddy/Caddyfile
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Check Caddy logs:**
|
||||||
|
```bash
|
||||||
|
docker logs caddy --tail 50
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Configuration
|
||||||
|
|
||||||
|
### Aggressive Fail2ban Settings
|
||||||
|
|
||||||
|
For tighter security:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[caddy-auth]
|
||||||
|
maxretry = 3 # Ban after 3 attempts (instead of 5)
|
||||||
|
findtime = 300 # Within 5 minutes (instead of 10)
|
||||||
|
bantime = 86400 # Ban for 24 hours (instead of 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ban Time Increment
|
||||||
|
|
||||||
|
Ban repeat offenders for longer:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[caddy-auth]
|
||||||
|
bantime.increment = true
|
||||||
|
bantime.factor = 24
|
||||||
|
bantime.maxtime = 604800 # Maximum 1 week ban
|
||||||
|
```
|
||||||
|
|
||||||
|
### Email Notifications
|
||||||
|
|
||||||
|
Get notified when IPs are banned:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[caddy-auth]
|
||||||
|
action = iptables-multiport[name=CaddyAuth, port="http,https", protocol=tcp]
|
||||||
|
sendmail-whois[name=CaddyAuth, dest=admin@yourdomain.com]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Per-Service Jails
|
||||||
|
|
||||||
|
Create separate jails for different services:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[caddy-actualbudget]
|
||||||
|
enabled = true
|
||||||
|
port = http,https
|
||||||
|
filter = caddy-auth
|
||||||
|
logpath = /var/log/caddy/actualbudget-access.log
|
||||||
|
maxretry = 3
|
||||||
|
bantime = 7200
|
||||||
|
|
||||||
|
[caddy-keycloak]
|
||||||
|
enabled = true
|
||||||
|
port = http,https
|
||||||
|
filter = caddy-auth
|
||||||
|
logpath = /var/log/caddy/keycloak-access.log
|
||||||
|
maxretry = 5
|
||||||
|
bantime = 3600
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Always backup before changes**
|
||||||
|
2. **Test configuration before reloading** (`caddy validate`)
|
||||||
|
3. **Monitor fail2ban logs** initially to tune settings
|
||||||
|
4. **Use strong passwords** for admin interfaces
|
||||||
|
5. **Keep services updated** (`docker compose pull && docker compose up -d`)
|
||||||
|
6. **Regular backups** of configuration and data
|
||||||
|
7. **Use HTTPS** via Caddy for all services
|
||||||
|
8. **Implement rate limiting** in Caddy for API endpoints
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
### Common Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Caddy
|
||||||
|
docker exec -w /etc/caddy caddy caddy reload
|
||||||
|
docker exec -w /etc/caddy caddy caddy fmt --overwrite
|
||||||
|
docker exec caddy caddy validate --config /etc/caddy/Caddyfile
|
||||||
|
docker logs caddy --tail 50
|
||||||
|
|
||||||
|
# Fail2ban
|
||||||
|
sudo systemctl restart fail2ban
|
||||||
|
sudo fail2ban-client status caddy-auth
|
||||||
|
sudo fail2ban-client set caddy-auth unbanip 1.2.3.4
|
||||||
|
sudo tail -f /var/log/fail2ban.log
|
||||||
|
|
||||||
|
# Backup
|
||||||
|
cp ~/docker/caddy/Caddyfile ~/docker/caddy/Caddyfile.backup
|
||||||
|
```
|
||||||
|
|
||||||
|
### Service Ports
|
||||||
|
|
||||||
|
- **ActualBudget**: 5006
|
||||||
|
- **Keycloak**: 8180
|
||||||
|
- **Caddy**: 80 (HTTP), 443 (HTTPS)
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues:
|
||||||
|
- Caddy documentation: https://caddyserver.com/docs/
|
||||||
|
- Fail2ban manual: https://www.fail2ban.org/wiki/index.php/MANUAL_0_8
|
||||||
|
- ActualBudget docs: https://actualbudget.org/docs/
|
||||||
|
- Keycloak docs: https://www.keycloak.org/documentation
|
||||||
Executable
+547
@@ -0,0 +1,547 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Caddy Setup Helper Script
|
||||||
|
# This script helps manage Caddy configuration, backups, and fail2ban integration
|
||||||
|
# for dockerized Caddy setups - FULLY AUTOMATED with error handling
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo "==============================================="
|
||||||
|
echo " Caddy Configuration & Fail2ban Setup Helper"
|
||||||
|
echo "==============================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Function to print colored output
|
||||||
|
print_info() {
|
||||||
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to ask yes/no questions
|
||||||
|
ask_yn() {
|
||||||
|
local prompt="$1"
|
||||||
|
local default="${2:-n}"
|
||||||
|
local response
|
||||||
|
|
||||||
|
if [ "$default" = "y" ]; then
|
||||||
|
read -p "$prompt [Y/n]: " response
|
||||||
|
response=${response:-y}
|
||||||
|
else
|
||||||
|
read -p "$prompt [y/N]: " response
|
||||||
|
response=${response:-n}
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ "$response" =~ ^[Yy]$ ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Track if we need to show manual instructions
|
||||||
|
SHOW_MANUAL=false
|
||||||
|
ERROR_MESSAGES=()
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 1. CHECK IF CADDY IS INSTALLED
|
||||||
|
# ==============================
|
||||||
|
print_info "Checking for Caddy installation..."
|
||||||
|
|
||||||
|
CADDY_CONTAINER=""
|
||||||
|
CADDYFILE_PATH=""
|
||||||
|
|
||||||
|
# Check if Docker is available
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
print_error "Docker is not installed or not in PATH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Try to find Caddy container
|
||||||
|
if docker ps --format '{{.Names}}' | grep -iq "caddy"; then
|
||||||
|
CADDY_CONTAINER=$(docker ps --format '{{.Names}}' | grep -i "caddy" | head -1)
|
||||||
|
print_success "Found running Caddy container: $CADDY_CONTAINER"
|
||||||
|
else
|
||||||
|
print_warning "No running Caddy container found"
|
||||||
|
if ! ask_yn "Is Caddy installed?" "n"; then
|
||||||
|
print_info "Caddy is not installed. Please install Caddy first."
|
||||||
|
echo ""
|
||||||
|
echo "To install Caddy with Docker, see CADDY-FAIL2BAN-SETUP.md"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 2. LOCATE CADDYFILE
|
||||||
|
# ==============================
|
||||||
|
print_info "Locating Caddyfile..."
|
||||||
|
|
||||||
|
# Common Caddyfile locations
|
||||||
|
POSSIBLE_PATHS=(
|
||||||
|
"$HOME/docker/caddy/Caddyfile"
|
||||||
|
"$HOME/docker/caddy/caddyfile"
|
||||||
|
"$HOME/docker/caddy/config/Caddyfile"
|
||||||
|
"/etc/caddy/Caddyfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
for path in "${POSSIBLE_PATHS[@]}"; do
|
||||||
|
if [ -f "$path" ]; then
|
||||||
|
CADDYFILE_PATH="$path"
|
||||||
|
print_success "Found Caddyfile at: $CADDYFILE_PATH"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$CADDYFILE_PATH" ]; then
|
||||||
|
print_warning "Caddyfile not found in common locations"
|
||||||
|
read -p "Enter path to Caddyfile: " CUSTOM_PATH
|
||||||
|
if [ -n "$CUSTOM_PATH" ] && [ -f "$CUSTOM_PATH" ]; then
|
||||||
|
CADDYFILE_PATH="$CUSTOM_PATH"
|
||||||
|
print_success "Using Caddyfile at: $CADDYFILE_PATH"
|
||||||
|
else
|
||||||
|
print_error "Cannot proceed without Caddyfile location"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
CADDY_DIR=$(dirname "$CADDYFILE_PATH")
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 3. BACKUP CADDYFILE (ALWAYS FIRST!)
|
||||||
|
# ==============================
|
||||||
|
print_info "Creating backup of Caddyfile..."
|
||||||
|
|
||||||
|
BACKUP_DIR="$CADDY_DIR/backups"
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
BACKUP_FILE="$BACKUP_DIR/Caddyfile.backup.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
cp "$CADDYFILE_PATH" "$BACKUP_FILE"
|
||||||
|
print_success "Backup created: $BACKUP_FILE"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo " BACKUP RESTORE INSTRUCTIONS"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo "To restore this backup:"
|
||||||
|
echo " cp $BACKUP_FILE $CADDYFILE_PATH"
|
||||||
|
if [ -n "$CADDY_CONTAINER" ]; then
|
||||||
|
echo " docker exec -w /etc/caddy $CADDY_CONTAINER caddy reload"
|
||||||
|
echo " docker exec -w /etc/caddy $CADDY_CONTAINER caddy fmt --overwrite"
|
||||||
|
fi
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 4. CHECK FOR FAIL2BAN INSTALLATION
|
||||||
|
# ==============================
|
||||||
|
print_info "Checking for fail2ban installation..."
|
||||||
|
|
||||||
|
FAIL2BAN_INSTALLED=false
|
||||||
|
if command -v fail2ban-client &> /dev/null; then
|
||||||
|
print_success "fail2ban is installed"
|
||||||
|
FAIL2BAN_INSTALLED=true
|
||||||
|
else
|
||||||
|
print_warning "fail2ban is not installed"
|
||||||
|
|
||||||
|
if ask_yn "Would you like to install fail2ban now?" "y"; then
|
||||||
|
print_info "Installing fail2ban..."
|
||||||
|
|
||||||
|
if sudo apt update && sudo apt install -y fail2ban; then
|
||||||
|
print_success "fail2ban installed successfully"
|
||||||
|
FAIL2BAN_INSTALLED=true
|
||||||
|
else
|
||||||
|
print_error "Failed to install fail2ban"
|
||||||
|
ERROR_MESSAGES+=("Failed to install fail2ban - you may need to install it manually")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_warning "Skipping fail2ban installation"
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 5. CREATE LOG DIRECTORY
|
||||||
|
# ==============================
|
||||||
|
if [ "$FAIL2BAN_INSTALLED" = true ]; then
|
||||||
|
print_info "Checking Caddy log directory..."
|
||||||
|
|
||||||
|
LOG_DIR="/var/log/caddy"
|
||||||
|
if [ ! -d "$LOG_DIR" ]; then
|
||||||
|
if ask_yn "Create $LOG_DIR for Caddy logs?" "y"; then
|
||||||
|
if sudo mkdir -p "$LOG_DIR" && sudo chmod 755 "$LOG_DIR"; then
|
||||||
|
print_success "Log directory created: $LOG_DIR"
|
||||||
|
else
|
||||||
|
print_error "Failed to create log directory"
|
||||||
|
ERROR_MESSAGES+=("Failed to create $LOG_DIR - create it manually with: sudo mkdir -p $LOG_DIR && sudo chmod 755 $LOG_DIR")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_success "Log directory exists: $LOG_DIR"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 6. CHECK CADDY DOCKER COMPOSE FOR LOG VOLUME
|
||||||
|
# ==============================
|
||||||
|
if [ "$FAIL2BAN_INSTALLED" = true ] && [ -n "$CADDY_CONTAINER" ]; then
|
||||||
|
print_info "Checking if Caddy container has log volume mounted..."
|
||||||
|
|
||||||
|
# Check if the container has /var/log/caddy mounted
|
||||||
|
if docker inspect "$CADDY_CONTAINER" 2>/dev/null | grep -q "/var/log/caddy"; then
|
||||||
|
print_success "Caddy container has log volume mounted"
|
||||||
|
else
|
||||||
|
print_warning "Caddy container does not have /var/log/caddy volume mounted"
|
||||||
|
|
||||||
|
# Check if there's a docker-compose.yml
|
||||||
|
COMPOSE_FILE=""
|
||||||
|
for file in "$CADDY_DIR/docker-compose.yml" "$CADDY_DIR/docker-compose.yaml"; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
COMPOSE_FILE="$file"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$COMPOSE_FILE" ]; then
|
||||||
|
if ask_yn "Add /var/log/caddy volume to docker-compose.yml?" "y"; then
|
||||||
|
# Backup docker-compose.yml
|
||||||
|
cp "$COMPOSE_FILE" "$COMPOSE_FILE.backup.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
|
||||||
|
# Check if volumes section exists
|
||||||
|
if grep -q "volumes:" "$COMPOSE_FILE"; then
|
||||||
|
# Add to existing volumes
|
||||||
|
if ! grep -q "/var/log/caddy" "$COMPOSE_FILE"; then
|
||||||
|
# Find the volumes section and add our volume
|
||||||
|
sed -i '/volumes:/a\ - /var/log/caddy:/var/log/caddy' "$COMPOSE_FILE"
|
||||||
|
print_success "Added log volume to docker-compose.yml"
|
||||||
|
print_warning "You'll need to restart the Caddy container for this to take effect"
|
||||||
|
|
||||||
|
if ask_yn "Restart Caddy container now?" "n"; then
|
||||||
|
cd "$CADDY_DIR"
|
||||||
|
if docker compose down && docker compose up -d; then
|
||||||
|
print_success "Caddy container restarted"
|
||||||
|
# Update CADDY_CONTAINER name in case it changed
|
||||||
|
CADDY_CONTAINER=$(docker ps --format '{{.Names}}' | grep -i "caddy" | head -1)
|
||||||
|
else
|
||||||
|
print_error "Failed to restart Caddy container"
|
||||||
|
ERROR_MESSAGES+=("Failed to restart Caddy - restart manually with: cd $CADDY_DIR && docker compose restart")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_warning "Could not automatically add volume - docker-compose.yml format is unexpected"
|
||||||
|
ERROR_MESSAGES+=("Add this volume manually to your Caddy service: /var/log/caddy:/var/log/caddy")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_warning "No docker-compose.yml found - you may need to add the volume manually"
|
||||||
|
ERROR_MESSAGES+=("Add log volume to Caddy container: /var/log/caddy:/var/log/caddy")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 7. CREATE FAIL2BAN FILTER
|
||||||
|
# ==============================
|
||||||
|
if [ "$FAIL2BAN_INSTALLED" = true ]; then
|
||||||
|
print_info "Checking fail2ban filter configuration..."
|
||||||
|
|
||||||
|
FILTER_FILE="/etc/fail2ban/filter.d/caddy-auth.conf"
|
||||||
|
if [ -f "$FILTER_FILE" ]; then
|
||||||
|
print_success "fail2ban filter already exists: $FILTER_FILE"
|
||||||
|
else
|
||||||
|
if ask_yn "Create fail2ban filter for Caddy?" "y"; then
|
||||||
|
print_info "Creating fail2ban filter..."
|
||||||
|
|
||||||
|
FILTER_CONTENT='[Definition]
|
||||||
|
failregex = ^.*"remote_ip":"<HOST>".*"status":(?:401|403|429).*$
|
||||||
|
^.*"remote_addr":"<HOST>.*"status":(?:401|403|429).*$
|
||||||
|
ignoreregex = ^.*"remote_ip":"(?:127\.0\.0\.1|::1)".*$
|
||||||
|
datepattern = "ts":%%s'
|
||||||
|
|
||||||
|
if echo "$FILTER_CONTENT" | sudo tee "$FILTER_FILE" > /dev/null; then
|
||||||
|
print_success "Created fail2ban filter: $FILTER_FILE"
|
||||||
|
else
|
||||||
|
print_error "Failed to create fail2ban filter"
|
||||||
|
ERROR_MESSAGES+=("Failed to create $FILTER_FILE - create it manually (see CADDY-FAIL2BAN-SETUP.md)")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 8. CREATE FAIL2BAN JAIL
|
||||||
|
# ==============================
|
||||||
|
if [ "$FAIL2BAN_INSTALLED" = true ]; then
|
||||||
|
print_info "Checking fail2ban jail configuration..."
|
||||||
|
|
||||||
|
JAIL_FILE="/etc/fail2ban/jail.d/caddy.conf"
|
||||||
|
if [ -f "$JAIL_FILE" ]; then
|
||||||
|
print_success "fail2ban jail already exists: $JAIL_FILE"
|
||||||
|
else
|
||||||
|
if ask_yn "Create fail2ban jail for Caddy?" "y"; then
|
||||||
|
print_info "Creating fail2ban jail..."
|
||||||
|
|
||||||
|
# Ask for custom settings
|
||||||
|
echo ""
|
||||||
|
print_info "Fail2ban jail settings (press Enter for defaults):"
|
||||||
|
read -p " Max retries before ban [5]: " MAXRETRY
|
||||||
|
MAXRETRY=${MAXRETRY:-5}
|
||||||
|
|
||||||
|
read -p " Find time window in seconds [600]: " FINDTIME
|
||||||
|
FINDTIME=${FINDTIME:-600}
|
||||||
|
|
||||||
|
read -p " Ban duration in seconds [3600]: " BANTIME
|
||||||
|
BANTIME=${BANTIME:-3600}
|
||||||
|
|
||||||
|
JAIL_CONTENT="[caddy-auth]
|
||||||
|
enabled = true
|
||||||
|
port = http,https
|
||||||
|
filter = caddy-auth
|
||||||
|
logpath = /var/log/caddy/access.log
|
||||||
|
/var/log/caddy/*-access.log
|
||||||
|
maxretry = $MAXRETRY
|
||||||
|
findtime = $FINDTIME
|
||||||
|
bantime = $BANTIME
|
||||||
|
action = iptables-multiport[name=CaddyAuth, port=\"http,https\", protocol=tcp]
|
||||||
|
backend = auto"
|
||||||
|
|
||||||
|
if echo "$JAIL_CONTENT" | sudo tee "$JAIL_FILE" > /dev/null; then
|
||||||
|
print_success "Created fail2ban jail: $JAIL_FILE"
|
||||||
|
else
|
||||||
|
print_error "Failed to create fail2ban jail"
|
||||||
|
ERROR_MESSAGES+=("Failed to create $JAIL_FILE - create it manually (see CADDY-FAIL2BAN-SETUP.md)")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 9. TEST FAIL2BAN CONFIGURATION
|
||||||
|
# ==============================
|
||||||
|
if [ "$FAIL2BAN_INSTALLED" = true ]; then
|
||||||
|
print_info "Testing fail2ban configuration..."
|
||||||
|
|
||||||
|
if sudo fail2ban-client -t &> /dev/null; then
|
||||||
|
print_success "fail2ban configuration is valid"
|
||||||
|
else
|
||||||
|
print_error "fail2ban configuration has errors"
|
||||||
|
ERROR_MESSAGES+=("fail2ban configuration is invalid - check with: sudo fail2ban-client -t")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 10. RESTART FAIL2BAN
|
||||||
|
# ==============================
|
||||||
|
if [ "$FAIL2BAN_INSTALLED" = true ]; then
|
||||||
|
if ask_yn "Restart fail2ban to apply changes?" "y"; then
|
||||||
|
print_info "Restarting fail2ban..."
|
||||||
|
|
||||||
|
if sudo systemctl restart fail2ban; then
|
||||||
|
print_success "fail2ban restarted successfully"
|
||||||
|
|
||||||
|
# Wait a moment for fail2ban to start
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Check if caddy-auth jail is running
|
||||||
|
if sudo fail2ban-client status caddy-auth &> /dev/null; then
|
||||||
|
print_success "caddy-auth jail is active"
|
||||||
|
echo ""
|
||||||
|
print_info "Jail status:"
|
||||||
|
sudo fail2ban-client status caddy-auth
|
||||||
|
else
|
||||||
|
print_warning "caddy-auth jail is not active"
|
||||||
|
ERROR_MESSAGES+=("caddy-auth jail failed to start - check with: sudo fail2ban-client status")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_error "Failed to restart fail2ban"
|
||||||
|
ERROR_MESSAGES+=("Failed to restart fail2ban - check logs with: sudo journalctl -u fail2ban -n 50")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 11. ADD SERVICE CONFIGURATIONS TO CADDYFILE
|
||||||
|
# ==============================
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo " ADDING NEW SERVICES TO CADDYFILE"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
print_info "You can now add your services to the Caddyfile"
|
||||||
|
echo ""
|
||||||
|
echo "Available services to add:"
|
||||||
|
echo " - ActualBudget (Personal Finance) - Port 5006"
|
||||||
|
echo " - Keycloak (Identity & Access Management) - Port 8180"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if ask_yn "Would you like to add ActualBudget to Caddyfile?" "n"; then
|
||||||
|
read -p "Enter domain for ActualBudget (e.g., budget.yourdomain.com): " AB_DOMAIN
|
||||||
|
|
||||||
|
if [ -n "$AB_DOMAIN" ]; then
|
||||||
|
AB_CONFIG="
|
||||||
|
# ActualBudget - Personal Finance
|
||||||
|
$AB_DOMAIN {
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/actualbudget-access.log
|
||||||
|
format json
|
||||||
|
level INFO
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse_proxy localhost:5006
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\"
|
||||||
|
X-Frame-Options \"SAMEORIGIN\"
|
||||||
|
X-Content-Type-Options \"nosniff\"
|
||||||
|
X-XSS-Protection \"1; mode=block\"
|
||||||
|
Referrer-Policy \"strict-origin-when-cross-origin\"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
|
||||||
|
if echo "$AB_CONFIG" >> "$CADDYFILE_PATH"; then
|
||||||
|
print_success "Added ActualBudget configuration to Caddyfile"
|
||||||
|
else
|
||||||
|
print_error "Failed to add ActualBudget configuration"
|
||||||
|
ERROR_MESSAGES+=("Add ActualBudget manually - see CADDY-FAIL2BAN-SETUP.md")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ask_yn "Would you like to add Keycloak to Caddyfile?" "n"; then
|
||||||
|
read -p "Enter domain for Keycloak (e.g., auth.yourdomain.com): " KC_DOMAIN
|
||||||
|
|
||||||
|
if [ -n "$KC_DOMAIN" ]; then
|
||||||
|
KC_CONFIG="
|
||||||
|
# Keycloak - Identity & Access Management
|
||||||
|
$KC_DOMAIN {
|
||||||
|
log {
|
||||||
|
output file /var/log/caddy/keycloak-access.log
|
||||||
|
format json
|
||||||
|
level INFO
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse_proxy localhost:8180
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
header {
|
||||||
|
Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\"
|
||||||
|
X-Frame-Options \"SAMEORIGIN\"
|
||||||
|
X-Content-Type-Options \"nosniff\"
|
||||||
|
X-XSS-Protection \"1; mode=block\"
|
||||||
|
Referrer-Policy \"strict-origin-when-cross-origin\"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
|
||||||
|
if echo "$KC_CONFIG" >> "$CADDYFILE_PATH"; then
|
||||||
|
print_success "Added Keycloak configuration to Caddyfile"
|
||||||
|
else
|
||||||
|
print_error "Failed to add Keycloak configuration"
|
||||||
|
ERROR_MESSAGES+=("Add Keycloak manually - see CADDY-FAIL2BAN-SETUP.md")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 12. VALIDATE AND RELOAD CADDY
|
||||||
|
# ==============================
|
||||||
|
if [ -n "$CADDY_CONTAINER" ]; then
|
||||||
|
echo ""
|
||||||
|
if ask_yn "Validate and reload Caddy configuration?" "y"; then
|
||||||
|
print_info "Validating Caddyfile..."
|
||||||
|
|
||||||
|
# Format first
|
||||||
|
if docker exec -w /etc/caddy "$CADDY_CONTAINER" caddy fmt --overwrite 2>/dev/null; then
|
||||||
|
print_success "Caddyfile formatted"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate
|
||||||
|
if docker exec "$CADDY_CONTAINER" caddy validate --config /etc/caddy/Caddyfile 2>/dev/null; then
|
||||||
|
print_success "Caddyfile is valid"
|
||||||
|
|
||||||
|
# Reload
|
||||||
|
print_info "Reloading Caddy configuration..."
|
||||||
|
if docker exec -w /etc/caddy "$CADDY_CONTAINER" caddy reload 2>/dev/null; then
|
||||||
|
print_success "Caddy configuration reloaded successfully"
|
||||||
|
else
|
||||||
|
print_error "Failed to reload Caddy configuration"
|
||||||
|
ERROR_MESSAGES+=("Failed to reload Caddy - check logs with: docker logs $CADDY_CONTAINER")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_error "Caddyfile validation failed"
|
||||||
|
ERROR_MESSAGES+=("Caddyfile has syntax errors - check with: docker exec $CADDY_CONTAINER caddy validate --config /etc/caddy/Caddyfile")
|
||||||
|
SHOW_MANUAL=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================
|
||||||
|
# 13. FINAL SUMMARY
|
||||||
|
# ==============================
|
||||||
|
echo ""
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo " SETUP COMPLETE"
|
||||||
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ "$SHOW_MANUAL" = true ]; then
|
||||||
|
print_warning "Some steps could not be completed automatically"
|
||||||
|
echo ""
|
||||||
|
echo "Issues encountered:"
|
||||||
|
for msg in "${ERROR_MESSAGES[@]}"; do
|
||||||
|
echo " - $msg"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
print_info "See CADDY-FAIL2BAN-SETUP.md for manual setup instructions"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Caddyfile backed up to: $BACKUP_FILE"
|
||||||
|
|
||||||
|
if [ "$FAIL2BAN_INSTALLED" = true ]; then
|
||||||
|
print_success "fail2ban is installed and configured"
|
||||||
|
echo ""
|
||||||
|
echo "Useful commands:"
|
||||||
|
echo " Check jail status: sudo fail2ban-client status caddy-auth"
|
||||||
|
echo " View banned IPs: sudo fail2ban-client get caddy-auth banip"
|
||||||
|
echo " Unban IP: sudo fail2ban-client set caddy-auth unbanip 1.2.3.4"
|
||||||
|
echo " Test filter: sudo fail2ban-regex /var/log/caddy/access.log /etc/fail2ban/filter.d/caddy-auth.conf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Caddyfile location: $CADDYFILE_PATH"
|
||||||
|
echo "Backup location: $BACKUP_FILE"
|
||||||
|
if [ -n "$CADDY_CONTAINER" ]; then
|
||||||
|
echo "Caddy container: $CADDY_CONTAINER"
|
||||||
|
echo "Reload Caddy: docker exec -w /etc/caddy $CADDY_CONTAINER caddy reload"
|
||||||
|
echo "View Caddy logs: docker logs $CADDY_CONTAINER --tail 50"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
print_success "All done!"
|
||||||
|
echo ""
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# ActualBudget - Open-source personal finance management
|
||||||
|
# https://actualbudget.org/
|
||||||
|
#
|
||||||
|
# DEPLOYMENT INSTRUCTIONS:
|
||||||
|
# 1. Create directory: mkdir -p ~/docker/actualbudget
|
||||||
|
# 2. Copy this file: cp docker-compose-actualbudget.yml ~/docker/actualbudget/docker-compose.yml
|
||||||
|
# 3. Create data directory: mkdir -p ~/docker/actualbudget/data
|
||||||
|
# 4. Start the service: cd ~/docker/actualbudget && docker compose up -d
|
||||||
|
# 5. Access at: http://localhost:5006
|
||||||
|
#
|
||||||
|
# REVERSE PROXY SETUP (with Caddy):
|
||||||
|
# Add to your Caddyfile:
|
||||||
|
# budget.yourdomain.com {
|
||||||
|
# reverse_proxy localhost:5006
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# BANK ACCOUNT SYNC:
|
||||||
|
# ActualBudget supports SimpleFIN (https://simplefin.org/) for bank synchronization.
|
||||||
|
# You'll need a SimpleFIN account to sync with your bank accounts.
|
||||||
|
# Setup instructions: https://actualbudget.org/docs/advanced/bank-sync
|
||||||
|
|
||||||
|
name: actualbudget
|
||||||
|
|
||||||
|
services:
|
||||||
|
actualbudget:
|
||||||
|
image: actualbudget/actual-server:latest
|
||||||
|
container_name: actualbudget
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "5006:5006"
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
environment:
|
||||||
|
# Set your timezone
|
||||||
|
- TZ=UTC
|
||||||
|
# Uncomment and set these for HTTPS/production deployment:
|
||||||
|
# - ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB=20
|
||||||
|
# - ACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB=50
|
||||||
|
# - ACTUAL_UPLOAD_FILE_SIZE_LIMIT_MB=20
|
||||||
|
labels:
|
||||||
|
# Fail2ban support - logs HTTP requests
|
||||||
|
- "io.podman.annotations.label/fail2ban.enable=true"
|
||||||
|
- "io.podman.annotations.label/fail2ban.filter=caddy-auth"
|
||||||
|
|
||||||
|
# NOTES:
|
||||||
|
# - Default port: 5006
|
||||||
|
# - Data stored in: ./data
|
||||||
|
# - First run: Create an account at http://localhost:5006
|
||||||
|
# - Bank sync requires SimpleFIN: https://simplefin.org/
|
||||||
|
# - Official docs: https://actualbudget.org/docs/
|
||||||
|
#
|
||||||
|
# BACKUP YOUR DATA:
|
||||||
|
# Regular backups are important! ActualBudget stores data in SQLite.
|
||||||
|
# docker compose down
|
||||||
|
# cp -r data data-backup-$(date +%Y%m%d)
|
||||||
|
# docker compose up -d
|
||||||
|
#
|
||||||
|
# UPDATES:
|
||||||
|
# docker compose pull
|
||||||
|
# docker compose up -d
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
# Keycloak - Open-source Identity and Access Management
|
||||||
|
# https://www.keycloak.org/
|
||||||
|
#
|
||||||
|
# DEPLOYMENT INSTRUCTIONS:
|
||||||
|
# 1. Create directory: mkdir -p ~/docker/keycloak
|
||||||
|
# 2. Copy this file: cp docker-compose-keycloak.yml ~/docker/keycloak/docker-compose.yml
|
||||||
|
# 3. IMPORTANT: Update KEYCLOAK_ADMIN_PASSWORD below!
|
||||||
|
# 4. Start the service: cd ~/docker/keycloak && docker compose up -d
|
||||||
|
# 5. Access at: http://localhost:8180/admin (admin console)
|
||||||
|
#
|
||||||
|
# REVERSE PROXY SETUP (with Caddy):
|
||||||
|
# Add to your Caddyfile:
|
||||||
|
# auth.yourdomain.com {
|
||||||
|
# reverse_proxy localhost:8180
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# PRODUCTION DEPLOYMENT:
|
||||||
|
# For production, you should:
|
||||||
|
# 1. Use a PostgreSQL database (see postgres service below)
|
||||||
|
# 2. Enable HTTPS via reverse proxy
|
||||||
|
# 3. Set KC_HOSTNAME to your domain
|
||||||
|
# 4. Use strong admin password
|
||||||
|
# 5. Configure proper realm and clients
|
||||||
|
|
||||||
|
name: keycloak
|
||||||
|
|
||||||
|
services:
|
||||||
|
# PostgreSQL database for Keycloak (recommended for production)
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: keycloak-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: keycloak
|
||||||
|
POSTGRES_USER: keycloak
|
||||||
|
POSTGRES_PASSWORD: keycloak_db_password_CHANGE_THIS
|
||||||
|
volumes:
|
||||||
|
- ./postgres-data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U keycloak"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
keycloak:
|
||||||
|
image: quay.io/keycloak/keycloak:latest
|
||||||
|
container_name: keycloak
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- start-dev # Use 'start' for production mode
|
||||||
|
environment:
|
||||||
|
# Admin credentials - CHANGE THESE!
|
||||||
|
- KEYCLOAK_ADMIN=admin
|
||||||
|
- KEYCLOAK_ADMIN_PASSWORD=CHANGE_THIS_SECURE_PASSWORD
|
||||||
|
|
||||||
|
# Database configuration (PostgreSQL)
|
||||||
|
- KC_DB=postgres
|
||||||
|
- KC_DB_URL=jdbc:postgresql://postgres:5432/keycloak
|
||||||
|
- KC_DB_USERNAME=keycloak
|
||||||
|
- KC_DB_PASSWORD=keycloak_db_password_CHANGE_THIS
|
||||||
|
|
||||||
|
# Hostname configuration
|
||||||
|
# For production, set to your domain:
|
||||||
|
# - KC_HOSTNAME=auth.yourdomain.com
|
||||||
|
# - KC_HOSTNAME_STRICT=true
|
||||||
|
- KC_HOSTNAME_STRICT=false
|
||||||
|
|
||||||
|
# Proxy configuration (required when behind Caddy/nginx)
|
||||||
|
- KC_PROXY=edge
|
||||||
|
- KC_HTTP_ENABLED=true
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
- KC_LOG_LEVEL=INFO
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
- KC_HEALTH_ENABLED=true
|
||||||
|
- KC_METRICS_ENABLED=true
|
||||||
|
ports:
|
||||||
|
- "8180:8080" # HTTP port (use reverse proxy for HTTPS)
|
||||||
|
# - "8787:8787" # Debug port (uncomment if needed)
|
||||||
|
volumes:
|
||||||
|
# Optional: Custom themes
|
||||||
|
# - ./themes:/opt/keycloak/themes
|
||||||
|
# Optional: Custom providers/extensions
|
||||||
|
# - ./providers:/opt/keycloak/providers
|
||||||
|
- ./data:/opt/keycloak/data
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
labels:
|
||||||
|
# Fail2ban support
|
||||||
|
- "io.podman.annotations.label/fail2ban.enable=true"
|
||||||
|
- "io.podman.annotations.label/fail2ban.filter=caddy-auth"
|
||||||
|
|
||||||
|
# NOTES:
|
||||||
|
# - Admin console: http://localhost:8180/admin
|
||||||
|
# - Default credentials: admin / CHANGE_THIS_SECURE_PASSWORD
|
||||||
|
# - Database: PostgreSQL (persistent data in ./postgres-data)
|
||||||
|
# - For H2 database (dev only), remove postgres service and database env vars
|
||||||
|
#
|
||||||
|
# FIRST-TIME SETUP:
|
||||||
|
# 1. Login to admin console
|
||||||
|
# 2. Create a realm (e.g., "myrealm")
|
||||||
|
# 3. Create clients for your applications
|
||||||
|
# 4. Configure authentication flows
|
||||||
|
# 5. Add users or configure identity providers (LDAP, SAML, OAuth)
|
||||||
|
#
|
||||||
|
# COMMON USE CASES:
|
||||||
|
# - Single Sign-On (SSO) for multiple applications
|
||||||
|
# - OAuth2/OIDC provider for custom apps
|
||||||
|
# - SAML 2.0 identity provider
|
||||||
|
# - User federation with LDAP/Active Directory
|
||||||
|
# - Multi-factor authentication (MFA/2FA)
|
||||||
|
# - Social login (Google, GitHub, etc.)
|
||||||
|
#
|
||||||
|
# PRODUCTION CHECKLIST:
|
||||||
|
# [ ] Change admin password
|
||||||
|
# [ ] Change database password
|
||||||
|
# [ ] Set KC_HOSTNAME to your domain
|
||||||
|
# [ ] Use 'start' instead of 'start-dev' command
|
||||||
|
# [ ] Configure HTTPS via reverse proxy (Caddy)
|
||||||
|
# [ ] Enable hostname strict mode
|
||||||
|
# [ ] Configure backup strategy for PostgreSQL
|
||||||
|
# [ ] Set up monitoring (metrics on port 9000)
|
||||||
|
#
|
||||||
|
# BACKUP:
|
||||||
|
# docker compose down
|
||||||
|
# tar -czf keycloak-backup-$(date +%Y%m%d).tar.gz postgres-data data
|
||||||
|
# docker compose up -d
|
||||||
|
#
|
||||||
|
# RESTORE:
|
||||||
|
# docker compose down
|
||||||
|
# tar -xzf keycloak-backup-YYYYMMDD.tar.gz
|
||||||
|
# docker compose up -d
|
||||||
|
#
|
||||||
|
# UPDATES:
|
||||||
|
# docker compose pull
|
||||||
|
# docker compose up -d
|
||||||
|
#
|
||||||
|
# DOCUMENTATION:
|
||||||
|
# - Official docs: https://www.keycloak.org/documentation
|
||||||
|
# - Getting started: https://www.keycloak.org/getting-started/getting-started-docker
|
||||||
|
# - Server admin: https://www.keycloak.org/docs/latest/server_admin/
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Fail2ban filter for Caddy web server
|
||||||
|
#
|
||||||
|
# INSTALLATION:
|
||||||
|
# 1. Copy this file to: /etc/fail2ban/filter.d/caddy-auth.conf
|
||||||
|
# sudo cp fail2ban-caddy-filter.conf /etc/fail2ban/filter.d/caddy-auth.conf
|
||||||
|
#
|
||||||
|
# 2. Create jail configuration at: /etc/fail2ban/jail.d/caddy.conf
|
||||||
|
# (See fail2ban-caddy-jail.conf in this directory)
|
||||||
|
#
|
||||||
|
# 3. Ensure Caddy is logging in JSON format to /var/log/caddy/access.log
|
||||||
|
# (See caddy-setup-helper.sh for configuration examples)
|
||||||
|
#
|
||||||
|
# 4. Restart fail2ban:
|
||||||
|
# sudo systemctl restart fail2ban
|
||||||
|
#
|
||||||
|
# 5. Check status:
|
||||||
|
# sudo fail2ban-client status caddy-auth
|
||||||
|
|
||||||
|
[INCLUDES]
|
||||||
|
before = common.conf
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
# Match failed authentication attempts and forbidden access
|
||||||
|
# Caddy JSON log format: {"remote_ip":"1.2.3.4","status":401,...}
|
||||||
|
failregex = ^.*"remote_ip":"<HOST>".*"status":(?:401|403|429).*$
|
||||||
|
^.*"remote_addr":"<HOST>.*"status":(?:401|403|429).*$
|
||||||
|
^.*"client_ip":"<HOST>".*"status":(?:401|403|429).*$
|
||||||
|
|
||||||
|
# Ignore localhost and common false positives
|
||||||
|
ignoreregex = ^.*"remote_ip":"(?:127\.0\.0\.1|::1)".*$
|
||||||
|
^.*"remote_addr":"(?:127\.0\.0\.1|::1)".*$
|
||||||
|
|
||||||
|
# Optional: Date/time pattern for log analysis
|
||||||
|
# Most Caddy JSON logs include "ts" field with Unix timestamp
|
||||||
|
datepattern = "ts":%%s
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
journalmatch = _SYSTEMD_UNIT=caddy.service
|
||||||
|
|
||||||
|
# NOTES:
|
||||||
|
# - This filter looks for HTTP status codes:
|
||||||
|
# 401 = Unauthorized (failed authentication)
|
||||||
|
# 403 = Forbidden (access denied)
|
||||||
|
# 429 = Too Many Requests (rate limiting)
|
||||||
|
#
|
||||||
|
# - Adjust the status codes based on your needs
|
||||||
|
# - For more aggressive blocking, add: 404|500
|
||||||
|
# - Test the filter: fail2ban-regex /var/log/caddy/access.log /etc/fail2ban/filter.d/caddy-auth.conf
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
# Fail2ban jail configuration for Caddy web server
|
||||||
|
#
|
||||||
|
# INSTALLATION:
|
||||||
|
# 1. Copy this file to: /etc/fail2ban/jail.d/caddy.conf
|
||||||
|
# sudo cp fail2ban-caddy-jail.conf /etc/fail2ban/jail.d/caddy.conf
|
||||||
|
#
|
||||||
|
# 2. Ensure the filter is installed:
|
||||||
|
# sudo cp fail2ban-caddy-filter.conf /etc/fail2ban/filter.d/caddy-auth.conf
|
||||||
|
#
|
||||||
|
# 3. Create log directory if it doesn't exist:
|
||||||
|
# sudo mkdir -p /var/log/caddy
|
||||||
|
# sudo chown caddy:caddy /var/log/caddy # Or appropriate user
|
||||||
|
#
|
||||||
|
# 4. Restart fail2ban:
|
||||||
|
# sudo systemctl restart fail2ban
|
||||||
|
#
|
||||||
|
# 5. Check status:
|
||||||
|
# sudo fail2ban-client status caddy-auth
|
||||||
|
|
||||||
|
[caddy-auth]
|
||||||
|
# Enable this jail
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
# Ports to protect (HTTP and HTTPS)
|
||||||
|
port = http,https
|
||||||
|
|
||||||
|
# Filter to use (must match filename in /etc/fail2ban/filter.d/)
|
||||||
|
filter = caddy-auth
|
||||||
|
|
||||||
|
# Log file to monitor
|
||||||
|
# Adjust this path if your Caddy logs are elsewhere
|
||||||
|
logpath = /var/log/caddy/access.log
|
||||||
|
/var/log/caddy/*-access.log
|
||||||
|
|
||||||
|
# For Docker Caddy, you might need to use Docker logs:
|
||||||
|
# logpath = /var/lib/docker/containers/*-caddy*/*.log
|
||||||
|
|
||||||
|
# Maximum retry before ban
|
||||||
|
# 5 attempts within findtime period will trigger a ban
|
||||||
|
maxretry = 5
|
||||||
|
|
||||||
|
# Time window (seconds) to count failures
|
||||||
|
# 600 = 10 minutes
|
||||||
|
findtime = 600
|
||||||
|
|
||||||
|
# Ban duration (seconds)
|
||||||
|
# 3600 = 1 hour
|
||||||
|
# 86400 = 24 hours
|
||||||
|
bantime = 3600
|
||||||
|
|
||||||
|
# Action to take when banning
|
||||||
|
# iptables-multiport: Block on multiple ports
|
||||||
|
action = iptables-multiport[name=CaddyAuth, port="http,https", protocol=tcp]
|
||||||
|
# Optional: Send email notification
|
||||||
|
# sendmail-whois[name=CaddyAuth, dest=admin@yourdomain.com]
|
||||||
|
|
||||||
|
# Backend to use for monitoring log file
|
||||||
|
# auto = automatically detect (systemd journal or file polling)
|
||||||
|
backend = auto
|
||||||
|
|
||||||
|
# OPTIONAL SETTINGS:
|
||||||
|
|
||||||
|
# Increase ban time on repeat offenders
|
||||||
|
# First ban: 1 hour, second: 24 hours, third: 1 week
|
||||||
|
# bantime.increment = true
|
||||||
|
# bantime.factor = 24
|
||||||
|
# bantime.maxtime = 604800 # 1 week max
|
||||||
|
|
||||||
|
# Find all jails using this ban
|
||||||
|
# This enables ban synchronization across jails
|
||||||
|
# banaction_allports = iptables-allports
|
||||||
|
|
||||||
|
# NOTES:
|
||||||
|
# - Adjust maxretry, findtime, and bantime based on your security needs
|
||||||
|
# - More aggressive: maxretry=3, findtime=300, bantime=86400
|
||||||
|
# - More lenient: maxretry=10, findtime=1200, bantime=1800
|
||||||
|
#
|
||||||
|
# TESTING:
|
||||||
|
# - Check if jail is running: sudo fail2ban-client status caddy-auth
|
||||||
|
# - View banned IPs: sudo fail2ban-client get caddy-auth banip
|
||||||
|
# - Unban an IP: sudo fail2ban-client set caddy-auth unbanip 1.2.3.4
|
||||||
|
# - Test filter: fail2ban-regex /var/log/caddy/access.log /etc/fail2ban/filter.d/caddy-auth.conf
|
||||||
+175
-10
@@ -2763,17 +2763,11 @@ MM_COMPOSE
|
|||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
# Run npm install for each downloaded module
|
# Run npm install for each downloaded module
|
||||||
|
# Note: This runs AFTER container is started, inside the container
|
||||||
echo ""
|
echo ""
|
||||||
echo " Installing npm dependencies for modules..."
|
echo " Note: Module dependencies will be installed when container starts"
|
||||||
for mod_dir in modules/MMM-*/; do
|
echo " If you need to manually install module dependencies, run:"
|
||||||
if [ -d "$mod_dir" ] && [ -f "$mod_dir/package.json" ]; then
|
echo " docker exec magicmirror-$MM_PORT sh -c 'cd /opt/magic_mirror/modules/<module-name> && npm install --production'"
|
||||||
mod_name=$(basename "$mod_dir")
|
|
||||||
echo " Installing dependencies for $mod_name..."
|
|
||||||
(cd "$mod_dir" && npm install --production 2>/dev/null) && \
|
|
||||||
echo " ✓ $mod_name dependencies installed" || \
|
|
||||||
echo " ⚠ $mod_name - npm install failed (may work anyway)"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -2877,6 +2871,21 @@ MM_CONFIG
|
|||||||
MM_PORT=$((8080 + i))
|
MM_PORT=$((8080 + i))
|
||||||
MM_DIR="$DOCKER_DIR/magicmirror-$MM_PORT"
|
MM_DIR="$DOCKER_DIR/magicmirror-$MM_PORT"
|
||||||
(cd "$MM_DIR" && docker compose up -d 2>/dev/null) && echo " ✓ Magic Mirror #$i started (port $MM_PORT)" || echo " ⚠ Failed to start Magic Mirror #$i"
|
(cd "$MM_DIR" && docker compose up -d 2>/dev/null) && echo " ✓ Magic Mirror #$i started (port $MM_PORT)" || echo " ⚠ Failed to start Magic Mirror #$i"
|
||||||
|
|
||||||
|
# Install npm dependencies for third-party modules inside container
|
||||||
|
if [ -d "$MM_DIR/modules" ]; then
|
||||||
|
echo " Installing module dependencies inside container..."
|
||||||
|
sleep 3 # Wait for container to fully start
|
||||||
|
for mod_dir in "$MM_DIR/modules"/MMM-*/; do
|
||||||
|
if [ -d "$mod_dir" ] && [ -f "$mod_dir/package.json" ]; then
|
||||||
|
mod_name=$(basename "$mod_dir")
|
||||||
|
echo " Installing $mod_name dependencies..."
|
||||||
|
docker exec magicmirror-$MM_PORT sh -c "cd /opt/magic_mirror/modules/$mod_name && npm install --production" 2>/dev/null && \
|
||||||
|
echo " ✓ $mod_name dependencies installed" || \
|
||||||
|
echo " ⚠ $mod_name - npm install failed (container may need restart)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -2886,6 +2895,162 @@ MM_CONFIG
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ---- ACTUALBUDGET ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ ACTUALBUDGET - Open-source Personal Finance Management │"
|
||||||
|
echo "│ Budget tracking with bank account synchronization via SimpleFIN│"
|
||||||
|
echo "│ Port: 5006 │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install ActualBudget? (y/n):" "n" INSTALL_ACTUALBUDGET
|
||||||
|
|
||||||
|
if [ "$INSTALL_ACTUALBUDGET" = "y" ] || [ "$INSTALL_ACTUALBUDGET" = "Y" ]; then
|
||||||
|
AB_DIR="$DOCKER_DIR/actualbudget"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $AB_DIR"
|
||||||
|
else
|
||||||
|
echo "Installing ActualBudget..."
|
||||||
|
mkdir -p "$AB_DIR/data"
|
||||||
|
cd "$AB_DIR"
|
||||||
|
|
||||||
|
cat > docker-compose.yml << 'AB_COMPOSE'
|
||||||
|
name: actualbudget
|
||||||
|
|
||||||
|
services:
|
||||||
|
actualbudget:
|
||||||
|
image: actualbudget/actual-server:latest
|
||||||
|
container_name: actualbudget
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "5006:5006"
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
environment:
|
||||||
|
- TZ=UTC
|
||||||
|
labels:
|
||||||
|
- "io.podman.annotations.label/fail2ban.enable=true"
|
||||||
|
- "io.podman.annotations.label/fail2ban.filter=caddy-auth"
|
||||||
|
AB_COMPOSE
|
||||||
|
|
||||||
|
echo " ✓ ActualBudget configured at $AB_DIR"
|
||||||
|
|
||||||
|
prompt_yn "Start ActualBudget now? (y/n):" "y" START_AB
|
||||||
|
if [ "$START_AB" = "y" ] || [ "$START_AB" = "Y" ]; then
|
||||||
|
docker compose up -d 2>/dev/null && echo " ✓ ActualBudget started" || echo " ⚠ Failed to start ActualBudget"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " Access at: http://localhost:5006"
|
||||||
|
echo " Bank sync: https://simplefin.org/ (SimpleFIN account required)"
|
||||||
|
echo " Data dir: $AB_DIR/data"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- KEYCLOAK ----
|
||||||
|
echo ""
|
||||||
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
echo "│ KEYCLOAK - Identity and Access Management (IAM) │"
|
||||||
|
echo "│ SSO, OAuth2, SAML, User Management, MFA │"
|
||||||
|
echo "│ Port: 8180 (HTTP) - Use reverse proxy for HTTPS │"
|
||||||
|
echo "└─────────────────────────────────────────────────────────────────┘"
|
||||||
|
prompt_yn "Install Keycloak? (y/n):" "n" INSTALL_KEYCLOAK
|
||||||
|
|
||||||
|
if [ "$INSTALL_KEYCLOAK" = "y" ] || [ "$INSTALL_KEYCLOAK" = "Y" ]; then
|
||||||
|
KC_DIR="$DOCKER_DIR/keycloak"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo "[DRY-RUN] Would create $KC_DIR"
|
||||||
|
else
|
||||||
|
echo "Installing Keycloak..."
|
||||||
|
echo ""
|
||||||
|
echo "⚠ SECURITY WARNING:"
|
||||||
|
echo " You MUST change the default admin password!"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
read -p "Enter Keycloak admin password [admin123]: " KC_ADMIN_PASS
|
||||||
|
KC_ADMIN_PASS=${KC_ADMIN_PASS:-admin123}
|
||||||
|
|
||||||
|
read -p "Enter database password [keycloak_db_pass]: " KC_DB_PASS
|
||||||
|
KC_DB_PASS=${KC_DB_PASS:-keycloak_db_pass}
|
||||||
|
|
||||||
|
mkdir -p "$KC_DIR/data" "$KC_DIR/postgres-data"
|
||||||
|
cd "$KC_DIR"
|
||||||
|
|
||||||
|
cat > docker-compose.yml << KC_COMPOSE
|
||||||
|
name: keycloak
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: keycloak-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: keycloak
|
||||||
|
POSTGRES_USER: keycloak
|
||||||
|
POSTGRES_PASSWORD: $KC_DB_PASS
|
||||||
|
volumes:
|
||||||
|
- ./postgres-data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U keycloak"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
keycloak:
|
||||||
|
image: quay.io/keycloak/keycloak:latest
|
||||||
|
container_name: keycloak
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- start-dev
|
||||||
|
environment:
|
||||||
|
- KEYCLOAK_ADMIN=admin
|
||||||
|
- KEYCLOAK_ADMIN_PASSWORD=$KC_ADMIN_PASS
|
||||||
|
- KC_DB=postgres
|
||||||
|
- KC_DB_URL=jdbc:postgresql://postgres:5432/keycloak
|
||||||
|
- KC_DB_USERNAME=keycloak
|
||||||
|
- KC_DB_PASSWORD=$KC_DB_PASS
|
||||||
|
- KC_HOSTNAME_STRICT=false
|
||||||
|
- KC_PROXY=edge
|
||||||
|
- KC_HTTP_ENABLED=true
|
||||||
|
- KC_LOG_LEVEL=INFO
|
||||||
|
- KC_HEALTH_ENABLED=true
|
||||||
|
- KC_METRICS_ENABLED=true
|
||||||
|
ports:
|
||||||
|
- "8180:8080"
|
||||||
|
volumes:
|
||||||
|
- ./data:/opt/keycloak/data
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
labels:
|
||||||
|
- "io.podman.annotations.label/fail2ban.enable=true"
|
||||||
|
- "io.podman.annotations.label/fail2ban.filter=caddy-auth"
|
||||||
|
KC_COMPOSE
|
||||||
|
|
||||||
|
echo " ✓ Keycloak configured at $KC_DIR"
|
||||||
|
|
||||||
|
prompt_yn "Start Keycloak now? (y/n):" "y" START_KC
|
||||||
|
if [ "$START_KC" = "y" ] || [ "$START_KC" = "Y" ]; then
|
||||||
|
echo " Starting Keycloak (this may take a minute)..."
|
||||||
|
docker compose up -d 2>/dev/null && echo " ✓ Keycloak started" || echo " ⚠ Failed to start Keycloak"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " Admin console: http://localhost:8180/admin"
|
||||||
|
echo " Username: admin"
|
||||||
|
echo " Password: $KC_ADMIN_PASS"
|
||||||
|
echo " Database: PostgreSQL (./postgres-data)"
|
||||||
|
echo ""
|
||||||
|
echo " ⚠ For production:"
|
||||||
|
echo " - Use HTTPS via reverse proxy (Caddy)"
|
||||||
|
echo " - Change command to 'start' instead of 'start-dev'"
|
||||||
|
echo " - Set KC_HOSTNAME to your domain"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# ---- LYRION MUSIC SERVER ----
|
# ---- LYRION MUSIC SERVER ----
|
||||||
echo ""
|
echo ""
|
||||||
echo "┌─────────────────────────────────────────────────────────────────┐"
|
echo "┌─────────────────────────────────────────────────────────────────┐"
|
||||||
|
|||||||
Reference in New Issue
Block a user