|
#!/bin/bash |
|
|
|
# Script to start a Redis container optionally with a stunnel container for TLS support based on the --tls flag. |
|
# It now generates URLs in the format compatible with Redis 6 ACL authentication. |
|
# Generates a unique ID, a secure password, finds free ports, and outputs ready-to-use Redis URLs. |
|
# Additionally, it creates a readonly user with ACLs. |
|
|
|
# Prerequisites: |
|
# - Docker installed and running |
|
# - Wildcard SSL certificate and key for your domain (if using TLS) |
|
|
|
log() { |
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" |
|
} |
|
|
|
# Initialize default values |
|
tls_enabled=0 |
|
redis_memory="256m" # Default memory value for Redis |
|
stunnel_memory="64m" # Default memory value for stunnel |
|
DOMAIN="redis.diegocornejo.com" # Adjust to your domain |
|
|
|
# Command-line options |
|
while [[ "$#" -gt 0 ]]; do |
|
case $1 in |
|
--tls) tls_enabled=1 ;; |
|
--redis-memory) redis_memory="$2"; shift ;; |
|
--stunnel-memory) stunnel_memory="$2"; shift ;; |
|
*) echo "Unknown parameter passed: $1"; exit 1 ;; |
|
esac |
|
shift |
|
done |
|
|
|
find_free_port() { |
|
local port=10000 |
|
while : ; do |
|
if ! sudo lsof -Pi :$port -sTCP:LISTEN -t >/dev/null 2>&1; then |
|
echo $port |
|
break |
|
fi |
|
((port++)) |
|
done |
|
} |
|
|
|
wait_for_redis() { |
|
local container_name=$1 |
|
log "Waiting for Redis container to be ready..." |
|
while ! docker exec "$container_name" redis-cli ping >/dev/null 2>&1; do |
|
log "Redis is not ready yet. Retrying in 2 seconds..." |
|
sleep 2 |
|
done |
|
log "Redis is ready!" |
|
} |
|
|
|
ID=$(uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]') |
|
PASSWORD=$(openssl rand -base64 16) |
|
READONLY_PASSWORD=$(openssl rand -base64 16) |
|
|
|
REDIS_PORT=$(find_free_port) |
|
VOLUME="redis-data-$ID" |
|
docker volume create "$VOLUME" |
|
|
|
docker run -d --name redis-$ID --memory="$redis_memory" -v "$VOLUME":/data -p "$REDIS_PORT":6379 \ |
|
redis redis-server --appendonly yes |
|
|
|
log "Redis container started." |
|
|
|
# Wait until Redis is ready before configuring ACLs |
|
wait_for_redis "redis-$ID" |
|
|
|
USERNAME="default" # Default username for Redis 6 ACL |
|
READONLY_USERNAME="readonly" |
|
HOSTNAME="$ID.$DOMAIN" |
|
|
|
# Create the ACLs for default and readonly users |
|
docker exec redis-$ID redis-cli ACL SETUSER $USERNAME on >"$PASSWORD" +@all |
|
docker exec redis-$ID redis-cli ACL SETUSER $READONLY_USERNAME on >"$READONLY_PASSWORD" ~* +get |
|
|
|
log "ACLs configured for default and readonly users." |
|
|
|
# Redis URL without TLS/SSL for both users |
|
log "Redis URL for default user: redis://$USERNAME:$PASSWORD@$HOSTNAME:$REDIS_PORT" |
|
log "Redis URL for readonly user: redis://$READONLY_USERNAME:$READONLY_PASSWORD@$HOSTNAME:$REDIS_PORT" |
|
|
|
if [ "$tls_enabled" -eq 1 ]; then |
|
CERT_PATH="/etc/letsencrypt/live/$DOMAIN/fullchain.pem" |
|
KEY_PATH="/etc/letsencrypt/live/$DOMAIN/privkey.pem" |
|
|
|
STUNNEL_PORT=$(find_free_port) |
|
while [[ "$STUNNEL_PORT" -eq "$REDIS_PORT" ]]; do |
|
log "Port $STUNNEL_PORT is in use. Finding another..." |
|
STUNNEL_PORT=$(find_free_port) |
|
done |
|
log "Using port $STUNNEL_PORT for stunnel." |
|
|
|
docker run -d --name stunnel-redis-$ID --memory="$stunnel_memory" \ |
|
-e STUNNEL_SERVICE=stunnel-redis-$ID \ |
|
-e STUNNEL_ACCEPT="$STUNNEL_PORT" \ |
|
-e STUNNEL_CONNECT="redis-$ID:$REDIS_PORT" \ |
|
-p "$STUNNEL_PORT":"$STUNNEL_PORT" \ |
|
-v "$CERT_PATH":/etc/stunnel/stunnel.pem:ro \ |
|
-v "$KEY_PATH":/etc/stunnel/stunnel.key:ro \ |
|
dweomer/stunnel |
|
|
|
log "stunnel container started on port $STUNNEL_PORT." |
|
|
|
# Redis URL with TLS/SSL for both users |
|
log "Secure Redis URL for default user: rediss://$USERNAME:$PASSWORD@$HOSTNAME:$STUNNEL_PORT" |
|
log "Secure Redis URL for readonly user: rediss://$READONLY_USERNAME:$READONLY_PASSWORD@$HOSTNAME:$STUNNEL_PORT" |
|
fi |