#!/bin/bash set -e echo "🚀 ReadMeABook Unified Container Starting..." # ============================================================================ # PUID/PGID USER REMAPPING (Hybrid approach) # ============================================================================ # Hybrid approach to support user file ownership while maintaining PostgreSQL compatibility: # - postgres user: Keep UID 103 (required by PostgreSQL), remap GID → PGID # - redis user: Remap UID → PUID, GID → PGID # - node user: Remap UID → PUID, GID → PGID # # Result: # - PostgreSQL data (103:PGID) - postgres user with shared group # - Redis/App/Downloads/Media (PUID:PGID) - your user owns everything else # - All files accessible via PGID group permissions PUID=${PUID:-} PGID=${PGID:-} if [ -n "$PUID" ] && [ -n "$PGID" ]; then echo "🔧 PUID/PGID detected - Configuring hybrid user mapping for $PUID:$PGID" echo "" # Get current UIDs/GIDs before remapping POSTGRES_UID=$(id -u postgres) POSTGRES_GID=$(id -g postgres) REDIS_UID=$(id -u redis) NODE_UID=$(id -u node) echo " Current UIDs: postgres=$POSTGRES_UID redis=$REDIS_UID node=$NODE_UID" echo "" echo " Applying hybrid mapping strategy:" echo " - postgres: Keep UID $POSTGRES_UID, remap GID → $PGID (PostgreSQL compatibility)" echo " - redis: Remap to $PUID:$PGID (full user ownership)" echo " - node: Remap to $PUID:$PGID (full user ownership)" echo "" # Step 1: Remap postgres group to PGID (keep UID 103 for PostgreSQL compatibility) echo " [1/3] Remapping postgres group to $PGID..." groupmod -o -g "$PGID" postgres 2>/dev/null || true # Postgres user keeps its UID but gets the new GID usermod -g "$PGID" postgres # Step 2: Remap redis user to PUID:PGID echo " [2/3] Remapping redis user to $PUID:$PGID..." groupmod -o -g "$PGID" redis 2>/dev/null || true usermod -o -u "$PUID" -g "$PGID" redis # Step 3: Remap node user to PUID:PGID echo " [3/3] Remapping node user to $PUID:$PGID..." groupmod -o -g "$PGID" node 2>/dev/null || true usermod -o -u "$PUID" -g "$PGID" node echo "" echo "✅ User mapping complete!" echo "" echo " File ownership will be:" echo " - PostgreSQL data (/var/lib/postgresql/data): $POSTGRES_UID:$PGID" echo " - Redis data (/var/lib/redis): $PUID:$PGID" echo " - App config (/app/config): $PUID:$PGID" echo " - Downloads (/downloads): $PUID:$PGID" echo " - Media (/media): $PUID:$PGID" echo "" echo " On your host, these will appear as:" echo " - PostgreSQL: UID $POSTGRES_UID, GID $PGID (readable via group)" echo " - Everything else: Your user ($PUID:$PGID)" echo "" # For LXC users, provide helpful mapping info if [ "$POSTGRES_UID" != "$PUID" ]; then echo " 📝 LXC Note: You need to map container UID $POSTGRES_UID to an accessible host UID" echo " Example lxc.idmap configuration:" echo " lxc.idmap: u 0 100000 $POSTGRES_UID" echo " lxc.idmap: g 0 100000 $POSTGRES_UID" echo " lxc.idmap: u $POSTGRES_UID $POSTGRES_UID 1 # Passthrough postgres UID" echo " lxc.idmap: g $POSTGRES_UID 100$POSTGRES_UID 1" echo " lxc.idmap: u $((POSTGRES_UID + 1)) 100$((POSTGRES_UID + 1)) 65432" echo " lxc.idmap: g $((POSTGRES_UID + 1)) 100$((POSTGRES_UID + 1)) 65432" echo "" fi else echo "â„šī¸ PUID/PGID not set - using default system user IDs" echo " Default ownership:" echo " - PostgreSQL data: postgres (UID 103)" echo " - Redis data: redis (UID 102)" echo " - App/Downloads: node (UID 1000)" echo "" echo " To customize ownership, set PUID and PGID environment variables" echo " Example: PUID=1000 PGID=1000" echo "" fi # ============================================================================ # GENERATE DEFAULT SECRETS IF NOT PROVIDED # ============================================================================ generate_secret() { openssl rand -base64 32 } # URL encode function for database password urlencode() { local string="$1" local strlen=${#string} local encoded="" local pos c o for (( pos=0 ; pos "$SECRETS_FILE" </dev/null; then echo "" echo "❌ ERROR: Failed to set ownership on PostgreSQL directories" echo "" echo " This usually happens when using bind mounts on incompatible filesystems." echo "" echo " Common causes:" echo " - WSL2: Project on Windows filesystem (/mnt/c/...)" echo " - NFS/CIFS: Mount without proper permission support" echo "" echo " Solutions:" echo "" echo " 1. Use Docker named volumes (recommended for WSL2):" echo " In docker-compose.yml, change:" echo " - ./pgdata:/var/lib/postgresql/data" echo " To:" echo " - pgdata:/var/lib/postgresql/data" echo " Then add at bottom:" echo " volumes:" echo " pgdata:" echo "" echo " 2. Move project to Linux filesystem (WSL2):" echo " mkdir -p ~/readmeabook && cd ~/readmeabook" echo " # Copy docker-compose.yml and restart" echo "" echo " 3. Pre-create directories with correct ownership:" echo " mkdir -p pgdata redis config cache" echo " # Let Docker create them on first run" echo "" exit 1 fi if [ -n "$PGID" ]; then # With PUID/PGID: Use 750 (owner rwx, group rx) for PostgreSQL data # This allows the PGID group to read PostgreSQL files if needed chmod 750 "$PGDATA" chmod 775 /var/run/postgresql else # Without PUID/PGID: Use strict 700 permissions (owner only) chmod 700 "$PGDATA" chmod 775 /var/run/postgresql fi # Redis directory - owned by redis user (remapped to PUID:PGID if set) if ! chown -R redis:redis /var/lib/redis 2>/dev/null; then echo "" echo "❌ ERROR: Failed to set ownership on Redis directory" echo " See solutions above for PostgreSQL directories" echo "" exit 1 fi chmod 770 /var/lib/redis # App directories - owned by node user (remapped to PUID:PGID if set) # These need group write permissions for shared access if ! chown -R node:node /app/config /app/cache 2>/dev/null; then echo "" echo "❌ ERROR: Failed to set ownership on app directories" echo " See solutions above for PostgreSQL directories" echo "" exit 1 fi chmod 775 /app/config /app/cache echo "✅ Directory permissions configured" if [ ! -f "$PGDATA/PG_VERSION" ]; then PG_WAS_EMPTY=1 echo "đŸ“Ļ Initializing PostgreSQL database..." su - postgres -c "/usr/lib/postgresql/16/bin/initdb -D $PGDATA" # Configure PostgreSQL for local access echo "host all all 127.0.0.1/32 trust" >> "$PGDATA/pg_hba.conf" echo "host all all ::1/128 trust" >> "$PGDATA/pg_hba.conf" echo "local all all trust" >> "$PGDATA/pg_hba.conf" # Update postgresql.conf for performance cat >> "$PGDATA/postgresql.conf" < /dev/null 2>&1; then echo "✅ PostgreSQL is ready" break fi echo "âŗ Waiting for PostgreSQL to be ready... ($i/30)" sleep 1 done # Always ensure user and database exist (safe due to IF NOT EXISTS checks) # This handles cases where data directory exists but user/database don't echo "👤 Ensuring database user and database exist..." su - postgres -c "psql -h 127.0.0.1 -U postgres" < /etc/environment <