Security Hardening Guide¶
Critical Security Issues¶
1. World-Readable .env Files (HIGH PRIORITY)¶
Current Issue: Several .env files have permissions 644 (world-readable), exposing sensitive credentials.
# Files with incorrect permissions:
-rw-r--r-- 1 root root /srv/dockerdata/supabase/.env
-rw-r--r-- 1 root root /srv/dockerdata/supabase/supabase.env
Immediate Fix Required:
# Fix all .env file permissions
find /srv/dockerdata -name "*.env" -type f -exec chmod 640 {} \;
find /srv/dockerdata -name "*.env" -type f -exec chown root:docker {} \;
# Verify fixes
find /srv/dockerdata -name "*.env" -type f -exec ls -la {} \;
2. Implement Security Audit Script¶
# Create security audit script
cat > /srv/dockerdata/_scripts/security-audit.sh << 'EOF'
#!/bin/bash
set -euo pipefail
REPORT_FILE="/var/log/security-audit-$(date +%Y%m%d).log"
ERRORS=0
echo "=== Docker Security Audit Report ===" | tee "$REPORT_FILE"
echo "Date: $(date)" | tee -a "$REPORT_FILE"
echo "" | tee -a "$REPORT_FILE"
# Check .env file permissions
echo "## Checking .env file permissions..." | tee -a "$REPORT_FILE"
while IFS= read -r -d '' file; do
perms=$(stat -c %a "$file")
owner=$(stat -c %U:%G "$file")
if [[ $perms -gt 640 ]]; then
echo "❌ CRITICAL: $file has permissions $perms (should be 640 or less)" | tee -a "$REPORT_FILE"
((ERRORS++))
else
echo "✓ $file: $perms $owner" | tee -a "$REPORT_FILE"
fi
done < <(find /srv/dockerdata -name "*.env" -type f -print0)
# Check for exposed ports
echo -e "\n## Checking for exposed ports..." | tee -a "$REPORT_FILE"
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep -E "0\.0\.0\.0:" | while read line; do
if ! echo "$line" | grep -q "traefik"; then
echo "⚠️ WARNING: $line" | tee -a "$REPORT_FILE"
fi
done
# Check for containers running as root
echo -e "\n## Checking for containers running as root..." | tee -a "$REPORT_FILE"
docker ps -q | while read container; do
user=$(docker inspect "$container" --format '{{.Config.User}}')
name=$(docker inspect "$container" --format '{{.Name}}' | sed 's/^\/\+//')
if [[ -z "$user" || "$user" == "root" ]]; then
echo "⚠️ WARNING: Container '$name' running as root" | tee -a "$REPORT_FILE"
fi
done
# Check for unused Docker resources
echo -e "\n## Checking for unused Docker resources..." | tee -a "$REPORT_FILE"
dangling_images=$(docker images -f "dangling=true" -q | wc -l)
dangling_volumes=$(docker volume ls -f "dangling=true" -q | wc -l)
echo "Dangling images: $dangling_images" | tee -a "$REPORT_FILE"
echo "Dangling volumes: $dangling_volumes" | tee -a "$REPORT_FILE"
# Check SSL certificates
echo -e "\n## Checking SSL certificates..." | tee -a "$REPORT_FILE"
if [[ -f /srv/dockerdata/traefik/letsencrypt/acme.json ]]; then
perms=$(stat -c %a /srv/dockerdata/traefik/letsencrypt/acme.json)
if [[ $perms != "600" ]]; then
echo "❌ CRITICAL: acme.json has permissions $perms (should be 600)" | tee -a "$REPORT_FILE"
((ERRORS++))
else
echo "✓ acme.json permissions correct (600)" | tee -a "$REPORT_FILE"
fi
fi
# Check for default passwords
echo -e "\n## Checking for common default passwords..." | tee -a "$REPORT_FILE"
grep -r "password\|secret\|changeme\|admin\|test\|demo" /srv/dockerdata/*.env 2>/dev/null | \
grep -v "POSTGRES_PASSWORD\|JWT_SECRET\|ANON_KEY\|SERVICE_ROLE_KEY" | \
while read line; do
echo "⚠️ Potential default password: $line" | tee -a "$REPORT_FILE"
done
# Summary
echo -e "\n## Summary" | tee -a "$REPORT_FILE"
if [[ $ERRORS -eq 0 ]]; then
echo "✓ No critical security issues found" | tee -a "$REPORT_FILE"
else
echo "❌ Found $ERRORS critical security issues!" | tee -a "$REPORT_FILE"
exit 1
fi
EOF
chmod +x /srv/dockerdata/_scripts/security-audit.sh
# Run initial audit
/srv/dockerdata/_scripts/security-audit.sh
Git Repository Security¶
Dual Repository Architecture¶
We maintain a secure dual-repository system that balances operational needs with public security:
- Gitea (Primary Repository)
- Self-hosted on our infrastructure
- Contains full Git history including sensitive files (.env, certificates, etc.)
- Provides complete version control for configuration management
- Accessible only through VPN or authenticated access
-
Used by internal team for development and operations
-
GitHub (Public Mirror)
- Automatically synced from Gitea with comprehensive filtering
- All sensitive files removed from entire Git history using git-filter-repo
- Secure for public access and open-source collaboration
- Force pushes are expected and normal due to history rewriting
- Read-only mirror - development happens on Gitea
Secret Detection and Filtering¶
The sync process uses industry-standard secret detection patterns from: - Gitleaks: Comprehensive regex-based secret scanning - TruffleHog: Entropy analysis and verified secret detection - detect-secrets: Baseline-based secret prevention - Custom patterns: Infrastructure-specific secret formats
Security Verification Process¶
Before any code reaches GitHub: 1. Complete Git history is cloned from Gitea 2. git-filter-repo removes all sensitive files from every commit 3. Comprehensive secret scanning verifies the cleaned repository 4. Only after passing all checks is the code pushed to GitHub
This ensures that secrets never exist in the public repository, not even in historical commits.
Secrets Management¶
1. Docker Secrets Setup¶
# Initialize Docker Swarm (if not already)
docker swarm init
# Create secrets from environment variables
cat > /srv/dockerdata/_scripts/create-secrets.sh << 'EOF'
#!/bin/bash
set -euo pipefail
# Function to create secret if it doesn't exist
create_secret() {
local name=$1
local value=$2
if ! docker secret ls | grep -q "^$name "; then
echo "$value" | docker secret create "$name" -
echo "✓ Created secret: $name"
else
echo "- Secret already exists: $name"
fi
}
# Load current environment variables
source /srv/dockerdata/supabase/supabase.env
# Create Docker secrets
create_secret "postgres_password" "$POSTGRES_PASSWORD"
create_secret "jwt_secret" "$JWT_SECRET"
create_secret "anon_key" "$ANON_KEY"
create_secret "service_role_key" "$SERVICE_ROLE_KEY"
create_secret "supabase_admin_password" "$DASHBOARD_PASSWORD"
# Traefik secrets
if [[ -f /srv/dockerdata/traefik/.env ]]; then
source /srv/dockerdata/traefik/.env
create_secret "cf_api_email" "$CF_API_EMAIL"
create_secret "cf_dns_api_token" "$CF_DNS_API_TOKEN"
fi
echo -e "\n✓ Secrets created. List all secrets:"
docker secret ls
EOF
chmod +x /srv/dockerdata/_scripts/create-secrets.sh
2. Migrate to Docker Secrets¶
# Example: Update Supabase to use secrets
version: '3.8'
services:
db:
image: supabase/postgres:15.8.1.122
secrets:
- postgres_password
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
secrets:
postgres_password:
external: true
3. HashiCorp Vault Integration (Advanced)¶
# Deploy Vault for production secrets management
cat > /srv/dockerdata/vault/docker-compose.yml << 'EOF'
version: '3.8'
services:
vault:
image: hashicorp/vault:latest
container_name: vault
restart: unless-stopped
cap_add:
- IPC_LOCK
environment:
VAULT_DEV_ROOT_TOKEN_ID: myroot
VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200
volumes:
- vault_data:/vault/data
- ./config:/vault/config
networks:
- secure
command: server
volumes:
vault_data:
networks:
secure:
driver: bridge
internal: true
EOF
Network Security¶
1. Implement Network Segmentation¶
# Create isolated networks
docker network create --internal internal_db
docker network create --internal internal_cache
docker network create dmz
# Update docker-compose files to use appropriate networks
# Example for Supabase:
cat > /srv/dockerdata/supabase/network-update.yml << 'EOF'
services:
db:
networks:
- internal_db
# Remove from traefik_proxy
supabase-auth:
networks:
- internal_db
- dmz
supabase-rest:
networks:
- internal_db
- dmz
- traefik_proxy
networks:
internal_db:
external: true
dmz:
external: true
traefik_proxy:
external: true
EOF
2. Implement Firewall Rules¶
# Install UFW if not present
sudo apt-get update && sudo apt-get install -y ufw
# Configure UFW
cat > /srv/dockerdata/_scripts/setup-firewall.sh << 'EOF'
#!/bin/bash
set -euo pipefail
# Default policies
ufw default deny incoming
ufw default allow outgoing
# Allow SSH (adjust port as needed)
ufw allow 22/tcp comment "SSH"
# Allow HTTP/HTTPS
ufw allow 80/tcp comment "HTTP"
ufw allow 443/tcp comment "HTTPS"
# Docker management (localhost only)
ufw allow from 127.0.0.1 to any port 2375 comment "Docker API"
ufw allow from 127.0.0.1 to any port 2376 comment "Docker TLS"
# Internal services (do not expose)
# PostgreSQL - internal only
ufw deny 5432/tcp comment "Block PostgreSQL"
# Monitoring (internal only)
ufw allow from 10.0.0.0/8 to any port 9090 comment "Prometheus"
ufw allow from 10.0.0.0/8 to any port 3000 comment "Grafana"
# Enable firewall
ufw --force enable
# Show status
ufw status verbose
EOF
chmod +x /srv/dockerdata/_scripts/setup-firewall.sh
3. Network Policies¶
# Example: Restrict database access
version: '3.8'
services:
db:
networks:
backend:
aliases:
- postgres
deploy:
endpoint_mode: dnsrr
app:
networks:
- frontend
- backend
depends_on:
- db
networks:
frontend:
external: true
backend:
driver: bridge
internal: true
driver_opts:
com.docker.network.bridge.enable_icc: "false"
SSL/TLS Configuration¶
1. Strengthen TLS Configuration¶
# Update Traefik static configuration
cat >> /srv/dockerdata/traefik/traefik.yml << 'EOF'
# TLS Options
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
curvePreferences:
- secp521r1
- secp384r1
sniStrict: true
strict:
minVersion: VersionTLS13
EOF
2. Certificate Monitoring¶
# Certificate expiry monitoring script
cat > /srv/dockerdata/_scripts/check-certificates.sh << 'EOF'
#!/bin/bash
set -euo pipefail
DAYS_WARNING=30
ALERT_EMAIL="[email protected]"
check_cert() {
local domain=$1
local port=${2:-443}
expiry=$(echo | openssl s_client -servername "$domain" -connect "$domain:$port" 2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
if [[ -n "$expiry" ]]; then
expiry_epoch=$(date -d "$expiry" +%s)
current_epoch=$(date +%s)
days_left=$(( (expiry_epoch - current_epoch) / 86400 ))
if [[ $days_left -lt $DAYS_WARNING ]]; then
echo "⚠️ WARNING: $domain certificate expires in $days_left days"
# Send alert
echo "Certificate for $domain expires in $days_left days" | \
mail -s "Certificate Expiry Warning" "$ALERT_EMAIL"
else
echo "✓ $domain: $days_left days until expiry"
fi
else
echo "❌ ERROR: Could not check certificate for $domain"
fi
}
# Check all domains
check_cert "supabase.rbnk.uk"
check_cert "grafana.rbnk.uk"
check_cert "traefik.rbnk.uk"
EOF
chmod +x /srv/dockerdata/_scripts/check-certificates.sh
# Add to cron
echo "0 9 * * * /srv/dockerdata/_scripts/check-certificates.sh" | crontab -
Container Security¶
1. Security Scanning¶
# Install Trivy for vulnerability scanning
cat > /srv/dockerdata/_scripts/scan-images.sh << 'EOF'
#!/bin/bash
set -euo pipefail
# Install Trivy if not present
if ! command -v trivy &> /dev/null; then
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | \
sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt-get update && sudo apt-get install -y trivy
fi
REPORT_DIR="/var/log/security-scans"
mkdir -p "$REPORT_DIR"
echo "=== Scanning Docker Images for Vulnerabilities ==="
# Scan all running containers
docker ps --format "{{.Image}}" | sort -u | while read image; do
echo "Scanning: $image"
report_file="$REPORT_DIR/$(echo $image | tr '/:' '_')-$(date +%Y%m%d).json"
trivy image --format json --output "$report_file" "$image" || true
# Check for critical vulnerabilities
critical=$(jq '[.Results[].Vulnerabilities[]? | select(.Severity=="CRITICAL")] | length' "$report_file")
high=$(jq '[.Results[].Vulnerabilities[]? | select(.Severity=="HIGH")] | length' "$report_file")
if [[ $critical -gt 0 ]]; then
echo "❌ CRITICAL: Found $critical critical vulnerabilities in $image"
elif [[ $high -gt 0 ]]; then
echo "⚠️ WARNING: Found $high high severity vulnerabilities in $image"
else
echo "✓ No critical/high vulnerabilities found"
fi
done
# Generate summary report
echo -e "\n=== Vulnerability Summary ===" > "$REPORT_DIR/summary-$(date +%Y%m%d).txt"
for report in "$REPORT_DIR"/*.json; do
[[ -f "$report" ]] || continue
image=$(basename "$report" .json | tr '_' '/')
critical=$(jq '[.Results[].Vulnerabilities[]? | select(.Severity=="CRITICAL")] | length' "$report")
high=$(jq '[.Results[].Vulnerabilities[]? | select(.Severity=="HIGH")] | length' "$report")
echo "$image - Critical: $critical, High: $high" >> "$REPORT_DIR/summary-$(date +%Y%m%d).txt"
done
cat "$REPORT_DIR/summary-$(date +%Y%m%d).txt"
EOF
chmod +x /srv/dockerdata/_scripts/scan-images.sh
2. Runtime Security¶
# Add security options to containers
version: '3.8'
services:
app:
image: myapp:latest
security_opt:
- no-new-privileges:true
- apparmor:docker-default
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
read_only: true
tmpfs:
- /tmp
- /var/run
user: "1000:1000"
3. Docker Daemon Hardening¶
# Update Docker daemon configuration
cat > /etc/docker/daemon.json << 'EOF'
{
"icc": false,
"userland-proxy": false,
"no-new-privileges": true,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"live-restore": true,
"userland-proxy": false,
"experimental": false,
"features": {
"buildkit": true
},
"metrics-addr": "127.0.0.1:9323"
}
EOF
# Restart Docker
sudo systemctl restart docker
API Key and Authentication Management¶
LiteLLM Virtual Keys Implementation¶
Our LiteLLM deployment uses Virtual Keys for enhanced security and cost tracking. This system provides:
- Individual Budget Limits: Each service has its own budget ($5-$20/month)
- Real-time Cost Tracking: Monitor usage and costs per service
- Security Isolation: Services cannot access each other's usage data
- Automated Alerting: Get notified when approaching budget limits
For complete implementation details, setup procedures, and management commands, see: LiteLLM Virtual Keys Implementation
Access Control¶
1. Implement RBAC¶
# Create user groups
sudo groupadd docker-readonly
sudo groupadd docker-admin
# Create restricted sudo rules
cat > /etc/sudoers.d/docker-access << 'EOF'
# Docker read-only access
%docker-readonly ALL=(ALL) NOPASSWD: /usr/bin/docker ps*, /usr/bin/docker logs*, /usr/bin/docker inspect*
# Docker admin access
%docker-admin ALL=(ALL) NOPASSWD: /usr/bin/docker *
# Deny direct database access
%docker-readonly ALL=(ALL) !/usr/bin/docker exec * psql *
%docker-readonly ALL=(ALL) !/usr/bin/docker exec * mysql *
EOF
2. Authentication Middleware¶
# Add to Traefik dynamic configuration
cat > /srv/dockerdata/traefik/dynamic/auth.yml << 'EOF'
http:
middlewares:
auth:
basicAuth:
users:
- "admin:$2y$10$..." # htpasswd -nB admin
realm: "Restricted Area"
oauth:
forwardAuth:
address: "http://oauth-proxy:4181"
trustForwardHeader: true
authResponseHeaders:
- "X-Forwarded-User"
rate-limit:
rateLimit:
average: 100
burst: 200
period: 1m
security-headers:
headers:
sslRedirect: true
stsSeconds: 31536000
stsIncludeSubdomains: true
stsPreload: true
forceSTSHeader: true
contentTypeNosniff: true
browserXssFilter: true
referrerPolicy: "same-origin"
featurePolicy: "geolocation 'none'; microphone 'none'; camera 'none'"
customResponseHeaders:
X-Robots-Tag: "noindex,nofollow,nosnippet,noarchive,notranslate,noimageindex"
EOF
Security Monitoring¶
1. Audit Logging¶
# Enable Docker audit logging
cat > /srv/dockerdata/_scripts/enable-audit-logging.sh << 'EOF'
#!/bin/bash
set -euo pipefail
# Install auditd if not present
sudo apt-get update && sudo apt-get install -y auditd
# Add Docker audit rules
cat >> /etc/audit/rules.d/docker.rules << 'AUDIT'
# Docker daemon
-w /usr/bin/dockerd -k docker
-w /usr/bin/docker -k docker
-w /var/lib/docker -k docker
-w /etc/docker -k docker
# Container runtime
-w /usr/bin/docker-containerd -k docker
-w /usr/bin/docker-runc -k docker
# Docker service
-w /lib/systemd/system/docker.service -k docker
-w /lib/systemd/system/docker.socket -k docker
# Docker config files
-w /etc/default/docker -k docker
-w /etc/docker/daemon.json -k docker
AUDIT
# Restart auditd
sudo service auditd restart
# Verify rules loaded
sudo auditctl -l | grep docker
EOF
chmod +x /srv/dockerdata/_scripts/enable-audit-logging.sh
2. Intrusion Detection¶
# Deploy Falco for runtime security
version: '3.8'
services:
falco:
image: falcosecurity/falco:latest
container_name: falco
privileged: true
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
- /dev:/host/dev
- /proc:/host/proc:ro
- /boot:/host/boot:ro
- /lib/modules:/host/lib/modules:ro
- ./falco/rules:/etc/falco/rules.d
environment:
- SKIP_DRIVER_LOADER=false
Security Checklist¶
Daily Tasks¶
- [ ] Review security audit logs
- [ ] Check for failed authentication attempts
- [ ] Monitor resource usage for anomalies
- [ ] Verify all services are running expected versions
Weekly Tasks¶
- [ ] Run vulnerability scans on all images
- [ ] Review and update access controls
- [ ] Check certificate expiration dates
- [ ] Audit user access and permissions
- [ ] Review firewall rules
Monthly Tasks¶
- [ ] Full security audit using audit script
- [ ] Update all container images
- [ ] Review and rotate secrets
- [ ] Test backup restoration
- [ ] Security training/awareness
Quarterly Tasks¶
- [ ] Penetration testing
- [ ] Review security policies
- [ ] Update incident response plan
- [ ] Compliance audit
Incident Response¶
1. Incident Response Plan¶
# Create incident response script
cat > /srv/dockerdata/_scripts/incident-response.sh << 'EOF'
#!/bin/bash
set -euo pipefail
INCIDENT_ID=$(date +%Y%m%d%H%M%S)
INCIDENT_DIR="/var/log/incidents/$INCIDENT_ID"
mkdir -p "$INCIDENT_DIR"
echo "=== Incident Response Started: $INCIDENT_ID ==="
# Collect system state
docker ps -a > "$INCIDENT_DIR/docker-ps.txt"
docker images > "$INCIDENT_DIR/docker-images.txt"
netstat -tulpn > "$INCIDENT_DIR/netstat.txt"
ps auxf > "$INCIDENT_DIR/processes.txt"
# Collect logs
docker logs --since 24h traefik > "$INCIDENT_DIR/traefik.log" 2>&1
journalctl --since "24 hours ago" > "$INCIDENT_DIR/system.log"
# Network connections
ss -tupn > "$INCIDENT_DIR/connections.txt"
# Check for suspicious files
find /srv/dockerdata -type f -mtime -1 -ls > "$INCIDENT_DIR/recent-files.txt"
echo "Incident data collected in: $INCIDENT_DIR"
EOF
chmod +x /srv/dockerdata/_scripts/incident-response.sh
2. Automated Response¶
# Automatic containment script
cat > /srv/dockerdata/_scripts/contain-threat.sh << 'EOF'
#!/bin/bash
set -euo pipefail
CONTAINER=$1
if [[ -z "$CONTAINER" ]]; then
echo "Usage: $0 <container_name>"
exit 1
fi
echo "⚠️ Containing potential threat in container: $CONTAINER"
# Disconnect from networks
docker network disconnect traefik_proxy "$CONTAINER" || true
# Stop container
docker stop "$CONTAINER"
# Create forensic copy
docker commit "$CONTAINER" "forensic/$CONTAINER:$(date +%Y%m%d%H%M%S)"
# Collect logs
docker logs "$CONTAINER" > "/var/log/incidents/$CONTAINER-$(date +%Y%m%d%H%M%S).log"
echo "✓ Container contained and evidence preserved"
EOF
chmod +x /srv/dockerdata/_scripts/contain-threat.sh
Compliance and Reporting¶
Generate Security Report¶
cat > /srv/dockerdata/_scripts/security-report.sh << 'EOF'
#!/bin/bash
set -euo pipefail
REPORT_FILE="/var/log/security-report-$(date +%Y%m).html"
cat > "$REPORT_FILE" << 'HTML'
<!DOCTYPE html>
<html>
<head>
<title>Security Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.pass { color: green; }
.fail { color: red; }
.warn { color: orange; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>Monthly Security Report</h1>
<p>Generated: $(date)</p>
HTML
# Add audit results
echo "<h2>Security Audit Results</h2>" >> "$REPORT_FILE"
/srv/dockerdata/_scripts/security-audit.sh >> "$REPORT_FILE" 2>&1
# Add vulnerability scan results
echo "<h2>Vulnerability Scan Summary</h2>" >> "$REPORT_FILE"
if [[ -f /var/log/security-scans/summary-*.txt ]]; then
echo "<pre>" >> "$REPORT_FILE"
cat /var/log/security-scans/summary-*.txt >> "$REPORT_FILE"
echo "</pre>" >> "$REPORT_FILE"
fi
echo "</body></html>" >> "$REPORT_FILE"
echo "Security report generated: $REPORT_FILE"
EOF
chmod +x /srv/dockerdata/_scripts/security-report.sh
Quick Security Fixes¶
# Run this script to apply immediate security fixes
cat > /srv/dockerdata/_scripts/quick-security-fix.sh << 'EOF'
#!/bin/bash
set -euo pipefail
echo "=== Applying Quick Security Fixes ==="
# 1. Fix file permissions
echo "Fixing .env file permissions..."
find /srv/dockerdata -name "*.env" -type f -exec chmod 640 {} \;
find /srv/dockerdata -name "*.env" -type f -exec chown root:docker {} \;
# 2. Fix certificate permissions
if [[ -f /srv/dockerdata/traefik/letsencrypt/acme.json ]]; then
chmod 600 /srv/dockerdata/traefik/letsencrypt/acme.json
fi
# 3. Remove unnecessary packages from containers
docker image prune -f
# 4. Update all containers to latest versions
echo "Pulling latest images..."
for compose in /srv/dockerdata/*/docker-compose.yml; do
dir=$(dirname "$compose")
cd "$dir"
docker compose pull
done
echo "✓ Quick security fixes applied"
echo "⚠️ Remember to restart services to apply updates"
EOF
chmod +x /srv/dockerdata/_scripts/quick-security-fix.sh
# Run it immediately
/srv/dockerdata/_scripts/quick-security-fix.sh