lthn.io/utils/scripts/redis-entrypoint.sh
Claude c89bee8e51
feat: add FrankenPHP + Octane Dockerfile and docker-compose
Copied production-quality Dockerfile from hostuk (FrankenPHP 1-php8.5,
Octane, Supervisor, Redis). Added docker-compose.yml with Traefik
labels for lthn.io, api.lthn.io, docs.lthn.io, explorer.lthn.io.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 10:36:42 +01:00

173 lines
5.1 KiB
Bash

#!/bin/sh
set -e
# Redis Multi-Host Replication Entrypoint
# Configures Redis as master or replica based on REDIS_NODES env var
# First IP in REDIS_NODES becomes master, all others are replicas
# Default values
REDIS_PORT=${REDIS_PORT:-6379}
REDIS_SENTINEL_PORT=${REDIS_SENTINEL_PORT:-26379}
REDIS_MASTER_NAME=${REDIS_MASTER_NAME:-hosthub}
REDIS_DIR=/data/redis
REDIS_CONF=/etc/redis.conf
SENTINEL_CONF=/etc/sentinel.conf
mkdir -p $REDIS_DIR
# Container-friendly Redis options (suppress kernel warnings we can't fix)
CONTAINER_OPTS="--stop-writes-on-bgsave-error no --save '' --appendonly no"
# If no REDIS_NODES and no REDIS_REPLICATION_KEY, run standalone without auth
if [ -z "$REDIS_NODES" ] && [ -z "$REDIS_REPLICATION_KEY" ]; then
echo "[Redis] No replication configured, running standalone (no auth)..."
redis-server --port $REDIS_PORT --dir $REDIS_DIR $CONTAINER_OPTS \
--loglevel warning --daemonize yes
# Wait for Redis to be ready before letting other services start
for i in 1 2 3 4 5; do
if redis-cli -p $REDIS_PORT ping 2>/dev/null | grep -q PONG; then
echo "[Redis] Standalone Redis is ready"
exit 0
fi
echo "[Redis] Waiting for Redis to start... ($i/5)"
sleep 1
done
echo "[Redis] Warning: Redis may not be fully ready"
exit 0
fi
# If no REDIS_NODES but has password, run standalone with auth
if [ -z "$REDIS_NODES" ]; then
echo "[Redis] Running standalone with authentication..."
redis-server --port $REDIS_PORT --dir $REDIS_DIR $CONTAINER_OPTS \
--loglevel warning --requirepass "$REDIS_REPLICATION_KEY" --daemonize yes
# Wait for Redis to be ready before letting other services start
for i in 1 2 3 4 5; do
if redis-cli -a "$REDIS_REPLICATION_KEY" -p $REDIS_PORT ping 2>/dev/null | grep -q PONG; then
echo "[Redis] Standalone Redis (with auth) is ready"
exit 0
fi
echo "[Redis] Waiting for Redis to start... ($i/5)"
sleep 1
done
echo "[Redis] Warning: Redis may not be fully ready"
exit 0
fi
# Replication mode - determine our role
echo "[Redis] Replication mode enabled"
echo "[Redis] Nodes: $REDIS_NODES"
# Get our IP - try multiple methods
MY_IP=$(hostname -i 2>/dev/null | awk '{print $1}')
if [ -z "$MY_IP" ]; then
MY_IP=$(ip route get 1 2>/dev/null | awk '{print $NF;exit}')
fi
if [ -z "$MY_IP" ]; then
MY_IP="127.0.0.1"
fi
MASTER_IP=$(echo $REDIS_NODES | cut -d',' -f1 | tr -d ' ')
echo "[Redis] My IP: $MY_IP, Master IP: $MASTER_IP"
# Generate redis.conf
cat > $REDIS_CONF <<EOF
# Redis Configuration - Auto-generated
port $REDIS_PORT
bind 0.0.0.0
dir $REDIS_DIR
requirepass $REDIS_REPLICATION_KEY
masterauth $REDIS_REPLICATION_KEY
# Persistence
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec
# Memory management
maxmemory 256mb
maxmemory-policy allkeys-lru
# Replication settings
replica-read-only yes
replica-serve-stale-data yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
EOF
# Determine role based on IP match
if [ "$MY_IP" = "$MASTER_IP" ]; then
echo "[Redis] Starting as MASTER"
ROLE="master"
else
echo "[Redis] Starting as REPLICA of $MASTER_IP:$REDIS_PORT"
ROLE="replica"
echo "replicaof $MASTER_IP $REDIS_PORT" >> $REDIS_CONF
fi
# Generate sentinel.conf
# Count nodes for quorum (majority needed)
NODE_COUNT=$(echo $REDIS_NODES | tr ',' '\n' | wc -l | tr -d ' ')
QUORUM=$(( (NODE_COUNT / 2) + 1 ))
echo "[Redis] Sentinel quorum: $QUORUM of $NODE_COUNT nodes"
cat > $SENTINEL_CONF <<EOF
# Sentinel Configuration - Auto-generated
port $REDIS_SENTINEL_PORT
bind 0.0.0.0
dir $REDIS_DIR
# Monitor the master
sentinel monitor $REDIS_MASTER_NAME $MASTER_IP $REDIS_PORT $QUORUM
sentinel auth-pass $REDIS_MASTER_NAME $REDIS_REPLICATION_KEY
# Timing settings
sentinel down-after-milliseconds $REDIS_MASTER_NAME 5000
sentinel failover-timeout $REDIS_MASTER_NAME 60000
sentinel parallel-syncs $REDIS_MASTER_NAME 1
# Announce our IP for proper failover
sentinel announce-ip $MY_IP
sentinel announce-port $REDIS_SENTINEL_PORT
EOF
# Add known sentinels (other nodes)
for NODE in $(echo $REDIS_NODES | tr ',' ' '); do
if [ "$NODE" != "$MY_IP" ]; then
echo "sentinel known-sentinel $REDIS_MASTER_NAME $NODE $REDIS_SENTINEL_PORT" >> $SENTINEL_CONF
fi
done
# Start Redis
echo "[Redis] Starting Redis server..."
redis-server $REDIS_CONF --daemonize yes
# Wait for Redis to be ready
sleep 2
if redis-cli -a "$REDIS_REPLICATION_KEY" ping 2>/dev/null | grep -q PONG; then
echo "[Redis] Redis is ready"
else
echo "[Redis] Warning: Redis may not be fully ready"
fi
# Start Sentinel
echo "[Redis] Starting Sentinel..."
redis-sentinel $SENTINEL_CONF --daemonize yes
# Wait for Sentinel
sleep 1
if redis-cli -p $REDIS_SENTINEL_PORT ping 2>/dev/null | grep -q PONG; then
echo "[Redis] Sentinel is ready"
# Show replication info
echo "[Redis] Replication status:"
redis-cli -a "$REDIS_REPLICATION_KEY" INFO replication 2>/dev/null | grep -E "^role:|^master_host:|^connected_slaves:" || true
else
echo "[Redis] Warning: Sentinel may not be fully ready"
fi
echo "[Redis] Setup complete (role: $ROLE)"