Refactor s6 config so each service has its separate run and type files (#1098)

This commit is contained in:
Leendert de Borst
2025-08-08 00:56:19 +02:00
committed by Leendert de Borst
parent af0b5ff5f8
commit 2d40e424e8
28 changed files with 343 additions and 284 deletions

View File

@@ -112,296 +112,20 @@ RUN sed -i 's/client:3000/localhost:3000/g' /etc/nginx/nginx.conf && \
sed -i 's/admin:3002/localhost:3002/g' /etc/nginx/nginx.conf
# ============================================
# S6 Service Definitions
# S6 Service Configuration
# ============================================
# Container initialization with secrets management
RUN mkdir -p /etc/s6-overlay/s6-rc.d/init-container && \
echo '#!/bin/sh' > /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'echo "[init-container] Initializing AliasVault single container..." >&2' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'echo "[init-container] Creating data directories..." >&2' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'mkdir -p /database/postgres /logs/postgres /certificates /secrets' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo '' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo '# Initialize secrets files if they dont exist' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'echo "[init-container] Initializing secrets..." >&2' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo '' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo '# Generate random 32 character password for PostgreSQL if not exists' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'if [ ! -f /secrets/postgres_password ]; then' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo ' echo "[init-container] Generating PostgreSQL password..." >&2' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo ' openssl rand -base64 32 | tr -d "\\n" > /secrets/postgres_password' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo ' chmod 600 /secrets/postgres_password' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'fi' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo '' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo '# Generate random 32 character password for Data Protection Certificate if not exists' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'if [ ! -f /secrets/data_protection_cert_pass ]; then' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo ' echo "[init-container] Generating Data Protection Certificate password..." >&2' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo ' openssl rand -base64 32 | tr -d "\\n" > /secrets/data_protection_cert_pass' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo ' chmod 600 /secrets/data_protection_cert_pass' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'fi' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo '' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo '# Generate JWT key if not exists' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'if [ ! -f /secrets/jwt_key ]; then' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo ' echo "[init-container] Generating JWT key..." >&2' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo ' openssl rand -base64 32 | tr -d "\\n" > /secrets/jwt_key' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo ' chmod 600 /secrets/jwt_key' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'fi' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo '' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'echo "[init-container] Setting database permissions..." >&2' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'chown -R postgres:postgres /database/postgres' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'chmod 700 /database/postgres' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo '' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
echo 'echo "[init-container] Container initialization complete" >&2' >> /etc/s6-overlay/s6-rc.d/init-container/up && \
chmod +x /etc/s6-overlay/s6-rc.d/init-container/up && \
echo "oneshot" > /etc/s6-overlay/s6-rc.d/init-container/type
# Copy s6 service definitions
COPY dockerfiles/s6-scripts /etc/s6-overlay/s6-rc.d/
# PostgreSQL service
RUN mkdir -p /etc/s6-overlay/s6-rc.d/postgres && \
{ echo '#!/bin/sh'; \
echo ''; \
echo '# Set PostgreSQL paths'; \
echo 'export PATH="/usr/lib/postgresql/16/bin:$PATH"'; \
echo 'export PGDATA="/database/postgres"'; \
echo ''; \
echo '# Read PostgreSQL password from file'; \
echo 'if [ -f /secrets/postgres_password ]; then'; \
echo ' POSTGRES_PASSWORD=$(cat /secrets/postgres_password)'; \
echo 'else'; \
echo ' # Fallback to environment variable or default'; \
echo ' POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-defaultpassword}"'; \
echo 'fi'; \
echo ''; \
echo '# Initialize PostgreSQL if needed'; \
echo 'if [ ! -d "$PGDATA/base" ]; then'; \
echo ' echo "Initializing PostgreSQL database..."'; \
echo ' mkdir -p "$PGDATA" /logs/postgres'; \
echo ' chown -R postgres:postgres "$PGDATA" /logs/postgres'; \
echo ' chmod 700 "$PGDATA"'; \
echo ' su - postgres -c "/usr/lib/postgresql/16/bin/initdb -D $PGDATA --locale=en_US.UTF-8 --encoding=UTF8"'; \
echo ' '; \
echo ' # Configure PostgreSQL'; \
echo ' echo "host all all 127.0.0.1/32 md5" >> "$PGDATA/pg_hba.conf"'; \
echo ' echo "listen_addresses = '\''127.0.0.1'\''" >> "$PGDATA/postgresql.conf"'; \
echo ' '; \
echo ' # Start PostgreSQL temporarily to create database and user'; \
echo ' su - postgres -c "/usr/lib/postgresql/16/bin/pg_ctl -D $PGDATA -l /logs/postgres/postgres.log start"'; \
echo ' sleep 5'; \
echo ' '; \
echo ' # Create database and user'; \
echo ' su - postgres -c "/usr/lib/postgresql/16/bin/psql -c \\"CREATE USER aliasvault WITH PASSWORD '\''$POSTGRES_PASSWORD'\''\\""'; \
echo ' su - postgres -c "/usr/lib/postgresql/16/bin/psql -c \\"CREATE DATABASE aliasvault OWNER aliasvault;\\""'; \
echo ' su - postgres -c "/usr/lib/postgresql/16/bin/psql -c \\"GRANT ALL PRIVILEGES ON DATABASE aliasvault TO aliasvault;\\""'; \
echo ' '; \
echo ' # Stop PostgreSQL'; \
echo ' su - postgres -c "/usr/lib/postgresql/16/bin/pg_ctl -D $PGDATA stop"'; \
echo ' sleep 2'; \
echo 'fi'; \
echo ''; \
echo '# Run PostgreSQL'; \
echo 'exec s6-setuidgid postgres /usr/lib/postgresql/16/bin/postgres -D "$PGDATA"'; \
} > /etc/s6-overlay/s6-rc.d/postgres/run && \
chmod +x /etc/s6-overlay/s6-rc.d/postgres/run && \
echo "longrun" > /etc/s6-overlay/s6-rc.d/postgres/type && \
mkdir -p /etc/s6-overlay/s6-rc.d/postgres/dependencies.d && \
touch /etc/s6-overlay/s6-rc.d/postgres/dependencies.d/init-container
# Make all scripts executable (run for longrun services, up for oneshot services, and script files)
RUN find /etc/s6-overlay/s6-rc.d -type f \( -name "run" -o -name "up" -o -name "script" \) -exec chmod +x {} \;
# API service
RUN mkdir -p /etc/s6-overlay/s6-rc.d/api && \
{ echo '#!/command/with-contenv bash'; \
echo 'cd /app/api'; \
echo '# Read PostgreSQL password from file'; \
echo 'if [ -f /secrets/postgres_password ]; then'; \
echo ' POSTGRES_PASSWORD=$(cat /secrets/postgres_password)'; \
echo 'else'; \
echo ' POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-defaultpassword}"'; \
echo 'fi'; \
echo '# Wait for PostgreSQL to be ready'; \
echo 'i=1; while [ $i -le 30 ]; do'; \
echo ' if PGPASSWORD="$POSTGRES_PASSWORD" /usr/lib/postgresql/16/bin/psql -h localhost -U aliasvault -d aliasvault -c "SELECT 1;" >/dev/null 2>&1; then'; \
echo ' echo "[api] PostgreSQL ready, starting API..." >&2; break'; \
echo ' fi'; \
echo ' echo "[api] Waiting for PostgreSQL ($i/30)..." >&2; sleep 2; i=$((i+1))'; \
echo 'done'; \
echo 'export ConnectionStrings__AliasServerDbContext="Host=localhost;Database=aliasvault;Username=aliasvault;Password=$POSTGRES_PASSWORD"'; \
echo 'export ASPNETCORE_URLS="http://0.0.0.0:3001"'; \
echo 'export ASPNETCORE_PATHBASE="/api"'; \
echo 'export PRIVATE_EMAIL_DOMAINS="${PRIVATE_EMAIL_DOMAINS:-}"'; \
echo 'export PUBLIC_REGISTRATION_ENABLED="${PUBLIC_REGISTRATION_ENABLED:-true}"'; \
echo 'export IP_LOGGING_ENABLED="${IP_LOGGING_ENABLED:-true}"'; \
echo 'exec dotnet AliasVault.Api.dll'; \
} > /etc/s6-overlay/s6-rc.d/api/run && \
chmod +x /etc/s6-overlay/s6-rc.d/api/run && \
echo "longrun" > /etc/s6-overlay/s6-rc.d/api/type
# Client service (nginx for WASM app) - using echo approach
RUN mkdir -p /etc/s6-overlay/s6-rc.d/client && \
{ echo '#!/command/with-contenv bash'; \
echo '# Client service entrypoint'; \
echo 'DEFAULT_PRIVATE_EMAIL_DOMAINS=""'; \
echo 'DEFAULT_SUPPORT_EMAIL=""'; \
echo 'PRIVATE_EMAIL_DOMAINS=${PRIVATE_EMAIL_DOMAINS:-$DEFAULT_PRIVATE_EMAIL_DOMAINS}'; \
echo 'SUPPORT_EMAIL=${SUPPORT_EMAIL:-$DEFAULT_SUPPORT_EMAIL}'; \
echo 'PUBLIC_REGISTRATION_ENABLED=${PUBLIC_REGISTRATION_ENABLED:-true}'; \
echo ''; \
echo 'mkdir -p /etc/nginx/ssl'; \
echo ''; \
echo 'if [ ! -f /etc/nginx/ssl/nginx.crt ] || [ ! -f /etc/nginx/ssl/nginx.key ]; then'; \
echo ' echo "Generating SSL certificate (10 years validity)..."'; \
echo ' openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt -subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"'; \
echo ' chmod 644 /etc/nginx/ssl/nginx.crt'; \
echo ' chmod 600 /etc/nginx/ssl/nginx.key'; \
echo 'fi'; \
echo ''; \
echo '# Create simple JSON with environment variables'; \
echo 'cat > /app/client/wwwroot/appsettings.json << EOF'; \
echo '{'; \
echo ' "PrivateEmailDomains": ["$PRIVATE_EMAIL_DOMAINS"],'; \
echo ' "SupportEmail": "$SUPPORT_EMAIL",'; \
echo ' "PublicRegistrationEnabled": "$PUBLIC_REGISTRATION_ENABLED"'; \
echo '}'; \
echo 'EOF'; \
echo ''; \
echo 'sed -i "s|/usr/share/nginx/html|/app/client/wwwroot|g" /app/client/nginx.conf'; \
echo ''; \
echo 'exec nginx -c /app/client/nginx.conf -g "daemon off;"'; \
} > /etc/s6-overlay/s6-rc.d/client/run && \
chmod +x /etc/s6-overlay/s6-rc.d/client/run && \
echo "longrun" > /etc/s6-overlay/s6-rc.d/client/type
# Admin service
RUN mkdir -p /etc/s6-overlay/s6-rc.d/admin && \
{ echo '#!/command/with-contenv bash'; \
echo 'cd /app/admin'; \
echo '# Read PostgreSQL password from file'; \
echo 'if [ -f /secrets/postgres_password ]; then'; \
echo ' POSTGRES_PASSWORD=$(cat /secrets/postgres_password)'; \
echo 'else'; \
echo ' POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-defaultpassword}"'; \
echo 'fi'; \
echo '# Wait for PostgreSQL to be ready'; \
echo 'i=1; while [ $i -le 30 ]; do'; \
echo ' if PGPASSWORD="$POSTGRES_PASSWORD" /usr/lib/postgresql/16/bin/psql -h localhost -U aliasvault -d aliasvault -c "SELECT 1;" >/dev/null 2>&1; then'; \
echo ' echo "[admin] PostgreSQL ready, starting Admin..." >&2; break'; \
echo ' fi'; \
echo ' echo "[admin] Waiting for PostgreSQL ($i/30)..." >&2; sleep 2; i=$((i+1))'; \
echo 'done'; \
echo 'export ConnectionStrings__AliasServerDbContext="Host=localhost;Database=aliasvault;Username=aliasvault;Password=$POSTGRES_PASSWORD"'; \
echo 'export ASPNETCORE_URLS="http://0.0.0.0:3002"'; \
echo 'export ASPNETCORE_PATHBASE="/admin"'; \
echo 'export IP_LOGGING_ENABLED="${IP_LOGGING_ENABLED:-true}"'; \
echo 'exec dotnet AliasVault.Admin.dll'; \
} > /etc/s6-overlay/s6-rc.d/admin/run && \
chmod +x /etc/s6-overlay/s6-rc.d/admin/run && \
echo "longrun" > /etc/s6-overlay/s6-rc.d/admin/type
# SMTP service
RUN mkdir -p /etc/s6-overlay/s6-rc.d/smtp && \
{ echo '#!/command/with-contenv bash'; \
echo 'cd /app/smtp'; \
echo '# Read PostgreSQL password from file'; \
echo 'if [ -f /secrets/postgres_password ]; then'; \
echo ' POSTGRES_PASSWORD=$(cat /secrets/postgres_password)'; \
echo 'else'; \
echo ' POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-defaultpassword}"'; \
echo 'fi'; \
echo '# Wait for PostgreSQL to be ready'; \
echo 'i=1; while [ $i -le 30 ]; do'; \
echo ' if PGPASSWORD="$POSTGRES_PASSWORD" /usr/lib/postgresql/16/bin/psql -h localhost -U aliasvault -d aliasvault -c "SELECT 1;" >/dev/null 2>&1; then'; \
echo ' echo "[smtp] PostgreSQL ready, starting SMTP..." >&2; break'; \
echo ' fi'; \
echo ' echo "[smtp] Waiting for PostgreSQL ($i/30)..." >&2; sleep 2; i=$((i+1))'; \
echo 'done'; \
echo 'export ConnectionStrings__AliasServerDbContext="Host=localhost;Database=aliasvault;Username=aliasvault;Password=$POSTGRES_PASSWORD"'; \
echo 'export PRIVATE_EMAIL_DOMAINS="${PRIVATE_EMAIL_DOMAINS:-}"'; \
echo 'export SMTP_TLS_ENABLED="${SMTP_TLS_ENABLED:-false}"'; \
echo 'exec dotnet AliasVault.SmtpService.dll'; \
} > /etc/s6-overlay/s6-rc.d/smtp/run && \
chmod +x /etc/s6-overlay/s6-rc.d/smtp/run && \
echo "longrun" > /etc/s6-overlay/s6-rc.d/smtp/type
# Task Runner service
RUN mkdir -p /etc/s6-overlay/s6-rc.d/taskrunner && \
{ echo '#!/command/with-contenv bash'; \
echo 'cd /app/taskrunner'; \
echo '# Read PostgreSQL password from file'; \
echo 'if [ -f /secrets/postgres_password ]; then'; \
echo ' POSTGRES_PASSWORD=$(cat /secrets/postgres_password)'; \
echo 'else'; \
echo ' POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-defaultpassword}"'; \
echo 'fi'; \
echo '# Wait for PostgreSQL to be ready'; \
echo 'i=1; while [ $i -le 30 ]; do'; \
echo ' if PGPASSWORD="$POSTGRES_PASSWORD" /usr/lib/postgresql/16/bin/psql -h localhost -U aliasvault -d aliasvault -c "SELECT 1;" >/dev/null 2>&1; then'; \
echo ' echo "[taskrunner] PostgreSQL ready, starting TaskRunner..." >&2; break'; \
echo ' fi'; \
echo ' echo "[taskrunner] Waiting for PostgreSQL ($i/30)..." >&2; sleep 2; i=$((i+1))'; \
echo 'done'; \
echo 'export ConnectionStrings__AliasServerDbContext="Host=localhost;Database=aliasvault;Username=aliasvault;Password=$POSTGRES_PASSWORD"'; \
echo 'exec dotnet AliasVault.TaskRunner.dll'; \
} > /etc/s6-overlay/s6-rc.d/taskrunner/run && \
chmod +x /etc/s6-overlay/s6-rc.d/taskrunner/run && \
echo "longrun" > /etc/s6-overlay/s6-rc.d/taskrunner/type
# Nginx service
RUN mkdir -p /etc/s6-overlay/s6-rc.d/nginx && \
{ echo '#!/command/with-contenv bash'; \
echo '# Generate SSL certificate if not exists'; \
echo 'if [ ! -f /certificates/ssl/cert.pem ]; then'; \
echo ' echo "Generating self-signed SSL certificate (10 years validity)..."'; \
echo ' mkdir -p /certificates/ssl'; \
echo ' openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \\'; \
echo ' -keyout /certificates/ssl/key.pem \\'; \
echo ' -out /certificates/ssl/cert.pem \\'; \
echo ' -subj "/C=US/ST=State/L=City/O=Organization/CN=${HOSTNAME:-localhost}"'; \
echo 'fi'; \
echo ''; \
echo '# Copy certificates to nginx directory'; \
echo 'cp /certificates/ssl/* /etc/nginx/ssl/ 2>/dev/null || true'; \
echo ''; \
echo '# Create SSL configuration file'; \
echo 'cat > /etc/nginx/ssl.conf << "SSLEOF"'; \
echo 'ssl_certificate /etc/nginx/ssl/cert.pem;'; \
echo 'ssl_certificate_key /etc/nginx/ssl/key.pem;'; \
echo 'ssl_session_timeout 1d;'; \
echo 'ssl_session_cache shared:MozTLS:10m;'; \
echo 'ssl_session_tickets off;'; \
echo 'ssl_protocols TLSv1.2 TLSv1.3;'; \
echo 'ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;'; \
echo 'ssl_prefer_server_ciphers off;'; \
echo 'SSLEOF'; \
echo ''; \
echo '# Use container nginx configuration'; \
echo 'cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf'; \
echo ''; \
echo '# Wait for all services to be ready'; \
echo 'echo "[nginx] Waiting for services to be ready..."'; \
echo 'i=1'; \
echo 'while [ $i -le 60 ]; do'; \
echo ' if nc -z localhost 3000 && nc -z localhost 3001 && nc -z localhost 3002; then'; \
echo ' echo "[nginx] All services ready, starting nginx..."'; \
echo ' break'; \
echo ' fi'; \
echo ' if [ $i -eq 60 ]; then'; \
echo ' echo "[nginx] Timeout waiting for services"'; \
echo ' exit 1'; \
echo ' fi'; \
echo ' echo "[nginx] Waiting for services ($i/60)..."'; \
echo ' sleep 1'; \
echo ' i=$(($i + 1))'; \
echo 'done'; \
echo ''; \
echo 'exec nginx -g "daemon off;"'; \
} > /etc/s6-overlay/s6-rc.d/nginx/run && \
chmod +x /etc/s6-overlay/s6-rc.d/nginx/run && \
echo "longrun" > /etc/s6-overlay/s6-rc.d/nginx/type && \
mkdir -p /etc/s6-overlay/s6-rc.d/nginx/dependencies.d && \
touch /etc/s6-overlay/s6-rc.d/nginx/dependencies.d/api && \
touch /etc/s6-overlay/s6-rc.d/nginx/dependencies.d/client && \
touch /etc/s6-overlay/s6-rc.d/nginx/dependencies.d/admin
# Service dependencies are now defined in the s6-scripts directory structure
# Enable all services in the default bundle
RUN mkdir -p /etc/s6-overlay/s6-rc.d/user/contents.d && \
touch /etc/s6-overlay/s6-rc.d/user/contents.d/init-container && \
touch /etc/s6-overlay/s6-rc.d/user/contents.d/init && \
touch /etc/s6-overlay/s6-rc.d/user/contents.d/postgres && \
touch /etc/s6-overlay/s6-rc.d/user/contents.d/api && \
touch /etc/s6-overlay/s6-rc.d/user/contents.d/client && \
@@ -412,7 +136,7 @@ RUN mkdir -p /etc/s6-overlay/s6-rc.d/user/contents.d && \
# Set environment variables for s6-overlay
ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
S6_VERBOSITY=1 \
S6_VERBOSITY=0 \
S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \
S6_KILL_GRACETIME=30000

View File

View File

@@ -0,0 +1,28 @@
#!/command/with-contenv bash
cd /app/admin
# Read PostgreSQL password from file
POSTGRES_PASSWORD=$(cat /secrets/postgres_password)
# Wait for PostgreSQL to be ready
echo "[admin] Waiting for PostgreSQL to be ready..."
for i in {1..30}; do
if PGPASSWORD="$POSTGRES_PASSWORD" /usr/lib/postgresql/16/bin/psql -h localhost -U aliasvault -d aliasvault -c "SELECT 1;" >/dev/null 2>&1; then
echo "[admin] PostgreSQL ready, starting Admin..."
break
fi
if [ $i -eq 30 ]; then
echo "[admin] Timeout waiting for PostgreSQL"
exit 1
fi
sleep 2
done
export ConnectionStrings__AliasServerDbContext="Host=localhost;Database=aliasvault;Username=aliasvault;Password=$POSTGRES_PASSWORD"
export ASPNETCORE_URLS="http://0.0.0.0:3002"
export ASPNETCORE_PATHBASE="/admin"
export IP_LOGGING_ENABLED="${IP_LOGGING_ENABLED:-true}"
echo "[admin] Starting Admin service..."
exec dotnet AliasVault.Admin.dll

View File

@@ -0,0 +1 @@
longrun

View File

View File

@@ -0,0 +1,30 @@
#!/command/with-contenv bash
cd /app/api
# Read PostgreSQL password from file
POSTGRES_PASSWORD=$(cat /secrets/postgres_password)
# Wait for PostgreSQL to be ready
echo "[api] Waiting for PostgreSQL to be ready..."
for i in {1..30}; do
if PGPASSWORD="$POSTGRES_PASSWORD" /usr/lib/postgresql/16/bin/psql -h localhost -U aliasvault -d aliasvault -c "SELECT 1;" >/dev/null 2>&1; then
echo "[api] PostgreSQL ready, starting API..."
break
fi
if [ $i -eq 30 ]; then
echo "[api] Timeout waiting for PostgreSQL"
exit 1
fi
sleep 2
done
export ConnectionStrings__AliasServerDbContext="Host=localhost;Database=aliasvault;Username=aliasvault;Password=$POSTGRES_PASSWORD"
export ASPNETCORE_URLS="http://0.0.0.0:3001"
export ASPNETCORE_PATHBASE="/api"
export PRIVATE_EMAIL_DOMAINS="${PRIVATE_EMAIL_DOMAINS:-}"
export PUBLIC_REGISTRATION_ENABLED="${PUBLIC_REGISTRATION_ENABLED:-true}"
export IP_LOGGING_ENABLED="${IP_LOGGING_ENABLED:-true}"
echo "[api] Starting API service..."
exec dotnet AliasVault.Api.dll

View File

@@ -0,0 +1 @@
longrun

View File

View File

@@ -0,0 +1,33 @@
#!/command/with-contenv bash
# Client service entrypoint
DEFAULT_PRIVATE_EMAIL_DOMAINS=""
DEFAULT_SUPPORT_EMAIL=""
PRIVATE_EMAIL_DOMAINS=${PRIVATE_EMAIL_DOMAINS:-$DEFAULT_PRIVATE_EMAIL_DOMAINS}
SUPPORT_EMAIL=${SUPPORT_EMAIL:-$DEFAULT_SUPPORT_EMAIL}
PUBLIC_REGISTRATION_ENABLED=${PUBLIC_REGISTRATION_ENABLED:-true}
mkdir -p /etc/nginx/ssl
if [ ! -f /etc/nginx/ssl/nginx.crt ] || [ ! -f /etc/nginx/ssl/nginx.key ]; then
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/nginx.key \
-out /etc/nginx/ssl/nginx.crt \
-subj "/C=US/ST=State/L=City/O=Organization/CN=localhost" >/dev/null 2>&1
chmod 644 /etc/nginx/ssl/nginx.crt
chmod 600 /etc/nginx/ssl/nginx.key
fi
# Create simple JSON with environment variables
cat > /app/client/wwwroot/appsettings.json << EOF
{
"PrivateEmailDomains": ["$PRIVATE_EMAIL_DOMAINS"],
"SupportEmail": "$SUPPORT_EMAIL",
"PublicRegistrationEnabled": "$PUBLIC_REGISTRATION_ENABLED"
}
EOF
sed -i "s|/usr/share/nginx/html|/app/client/wwwroot|g" /app/client/nginx.conf
echo "[client] Starting Client service (nginx)..."
exec nginx -c /app/client/nginx.conf -g "daemon off;"

View File

@@ -0,0 +1 @@
longrun

View File

View File

@@ -0,0 +1,139 @@
#!/bin/sh -e
# AliasVault Container Initialization Script
# This script runs once at container startup and handles all initialization tasks
# Print AliasVault header
echo ""
echo "=================================================="
echo " _ _ _ __ __ _ _ "
echo " / \\ | (_) __ _ ___ \\ \\ / /_ _ _ _| | |_"
echo " / _ \\ | | |/ _\` / __| \\ \\/\\/ / _\` | | | | | __|"
echo " / ___ \\| | | (_| \\__ \\ \\ / / (_| | |_| | | |_ "
echo "/_/ \\_\\_|_|\\__,_|___/ \\/ \\__,__|\\__,_|_|\\__|"
echo ""
echo "=================================================="
echo ""
echo "[init] Starting AliasVault container initialization..."
echo ""
# Create required directories
echo "[init] Creating required directories..."
mkdir -p /database/postgres /logs/postgres /certificates /secrets /var/run/postgresql
# Initialize secrets if they don't exist
echo "[init] Checking and initializing secrets..."
if [ ! -f /secrets/postgres_password ]; then
echo "[init] → Generating PostgreSQL password..."
openssl rand -base64 32 | tr -d "\n" > /secrets/postgres_password
chmod 600 /secrets/postgres_password
else
echo "[init] → PostgreSQL password already exists"
fi
if [ ! -f /secrets/data_protection_cert_pass ]; then
echo "[init] → Generating Data Protection Certificate password..."
openssl rand -base64 32 | tr -d "\n" > /secrets/data_protection_cert_pass
chmod 600 /secrets/data_protection_cert_pass
else
echo "[init] → Data Protection Certificate password already exists"
fi
if [ ! -f /secrets/jwt_key ]; then
echo "[init] → Generating JWT key..."
openssl rand -base64 32 | tr -d "\n" > /secrets/jwt_key
chmod 600 /secrets/jwt_key
else
echo "[init] → JWT key already exists"
fi
# Read PostgreSQL password for database initialization
POSTGRES_PASSWORD=$(cat /secrets/postgres_password)
export PGDATA="/database/postgres"
# Initialize PostgreSQL if needed
if [ ! -d "$PGDATA/base" ]; then
echo ""
echo "[init] PostgreSQL database not found, initializing..."
# Set proper permissions
chown -R postgres:postgres /database/postgres /logs/postgres /var/run/postgresql
chmod 700 /database/postgres
# Initialize database as postgres user
echo "[init] → Running initdb..."
su - postgres -c "/usr/lib/postgresql/16/bin/initdb -D $PGDATA --locale=en_US.UTF-8 --encoding=UTF8" > /logs/postgres/initdb.log 2>&1
# Configure PostgreSQL
echo "[init] → Configuring PostgreSQL..."
echo "host all all 127.0.0.1/32 md5" >> "$PGDATA/pg_hba.conf"
echo "listen_addresses = '127.0.0.1'" >> "$PGDATA/postgresql.conf"
# Start PostgreSQL temporarily to create database and user
echo "[init] → Starting PostgreSQL temporarily for setup..."
su - postgres -c "/usr/lib/postgresql/16/bin/pg_ctl -D $PGDATA -l /logs/postgres/postgres.log start"
# Wait for PostgreSQL to be ready
echo "[init] → Waiting for PostgreSQL to be ready..."
i=1
while [ $i -le 30 ]; do
if su - postgres -c "/usr/lib/postgresql/16/bin/psql -c 'SELECT 1;'" >/dev/null 2>&1; then
break
fi
sleep 1
i=$((i + 1))
done
# Create database and user
echo "[init] → Creating AliasVault database and user..."
su - postgres -c "/usr/lib/postgresql/16/bin/psql -c \"CREATE USER aliasvault WITH PASSWORD '$POSTGRES_PASSWORD'\""
su - postgres -c "/usr/lib/postgresql/16/bin/psql -c \"CREATE DATABASE aliasvault OWNER aliasvault;\""
su - postgres -c "/usr/lib/postgresql/16/bin/psql -c \"GRANT ALL PRIVILEGES ON DATABASE aliasvault TO aliasvault;\""
# Stop PostgreSQL
echo "[init] → Stopping PostgreSQL..."
su - postgres -c "/usr/lib/postgresql/16/bin/pg_ctl -D $PGDATA stop"
sleep 2
echo "[init] → PostgreSQL initialization complete"
else
echo "[init] PostgreSQL database already initialized"
# Just ensure permissions are correct
chown -R postgres:postgres /database/postgres /logs/postgres /var/run/postgresql
chmod 700 /database/postgres
fi
# Future: Database migrations could go here
# echo "[init] Checking for database migrations..."
# if [ -f /app/migrations/pending ]; then
# echo "[init] → Running database migrations..."
# # Run migration logic here
# fi
# Generate SSL certificates if needed
if [ ! -f /certificates/ssl/cert.pem ] || [ ! -f /certificates/ssl/key.pem ]; then
echo ""
echo "[init] Generating SSL certificates..."
mkdir -p /certificates/ssl
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /certificates/ssl/key.pem \
-out /certificates/ssl/cert.pem \
-subj "/C=US/ST=State/L=City/O=AliasVault/CN=${HOSTNAME:-localhost}" \
>/dev/null 2>&1
chmod 600 /certificates/ssl/key.pem
chmod 644 /certificates/ssl/cert.pem
echo "[init] → SSL certificates generated"
else
echo "[init] SSL certificates already exist"
fi
echo ""
echo "[init] ========================================="
echo "[init] AliasVault initialization complete!"
echo "[init] ========================================="
echo ""
# Oneshot service exits successfully, dependencies can now start

View File

@@ -0,0 +1 @@
oneshot

View File

@@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init/script

View File

View File

View File

View File

@@ -0,0 +1,34 @@
#!/command/with-contenv bash
# Copy certificates to nginx directory (they were created during init)
mkdir -p /etc/nginx/ssl
cp /certificates/ssl/* /etc/nginx/ssl/ 2>/dev/null || true
# Create SSL configuration file
cat > /etc/nginx/ssl.conf << "SSLEOF"
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:MozTLS:10m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
SSLEOF
# Wait for all services to be ready
echo "[nginx] Waiting for services to be ready..."
for i in {1..60}; do
if nc -z localhost 3000 && nc -z localhost 3001 && nc -z localhost 3002; then
echo "[nginx] All services ready, starting reverse proxy..."
break
fi
if [ $i -eq 60 ]; then
echo "[nginx] Timeout waiting for services"
exit 1
fi
sleep 1
done
echo "[nginx] Starting reverse proxy..."
exec nginx -g "daemon off;"

View File

@@ -0,0 +1 @@
longrun

View File

View File

@@ -0,0 +1,10 @@
#!/bin/sh
# Set PostgreSQL paths
export PATH="/usr/lib/postgresql/16/bin:$PATH"
export PGDATA="/database/postgres"
echo "[postgres] Starting PostgreSQL server..."
# Run PostgreSQL as postgres user
exec s6-setuidgid postgres /usr/lib/postgresql/16/bin/postgres -D "$PGDATA"

View File

@@ -0,0 +1 @@
longrun

View File

View File

@@ -0,0 +1,27 @@
#!/command/with-contenv bash
cd /app/smtp
# Read PostgreSQL password from file
POSTGRES_PASSWORD=$(cat /secrets/postgres_password)
# Wait for PostgreSQL to be ready
echo "[smtp] Waiting for PostgreSQL to be ready..."
for i in {1..30}; do
if PGPASSWORD="$POSTGRES_PASSWORD" /usr/lib/postgresql/16/bin/psql -h localhost -U aliasvault -d aliasvault -c "SELECT 1;" >/dev/null 2>&1; then
echo "[smtp] PostgreSQL ready, starting SMTP..."
break
fi
if [ $i -eq 30 ]; then
echo "[smtp] Timeout waiting for PostgreSQL"
exit 1
fi
sleep 2
done
export ConnectionStrings__AliasServerDbContext="Host=localhost;Database=aliasvault;Username=aliasvault;Password=$POSTGRES_PASSWORD"
export PRIVATE_EMAIL_DOMAINS="${PRIVATE_EMAIL_DOMAINS:-}"
export SMTP_TLS_ENABLED="${SMTP_TLS_ENABLED:-false}"
echo "[smtp] Starting SMTP service..."
exec dotnet AliasVault.SmtpService.dll

View File

@@ -0,0 +1 @@
longrun

View File

View File

@@ -0,0 +1,25 @@
#!/command/with-contenv bash
cd /app/taskrunner
# Read PostgreSQL password from file
POSTGRES_PASSWORD=$(cat /secrets/postgres_password)
# Wait for PostgreSQL to be ready
echo "[taskrunner] Waiting for PostgreSQL to be ready..."
for i in {1..30}; do
if PGPASSWORD="$POSTGRES_PASSWORD" /usr/lib/postgresql/16/bin/psql -h localhost -U aliasvault -d aliasvault -c "SELECT 1;" >/dev/null 2>&1; then
echo "[taskrunner] PostgreSQL ready, starting TaskRunner..."
break
fi
if [ $i -eq 30 ]; then
echo "[taskrunner] Timeout waiting for PostgreSQL"
exit 1
fi
sleep 2
done
export ConnectionStrings__AliasServerDbContext="Host=localhost;Database=aliasvault;Username=aliasvault;Password=$POSTGRES_PASSWORD"
echo "[taskrunner] Starting TaskRunner service..."
exec dotnet AliasVault.TaskRunner.dll

View File

@@ -0,0 +1 @@
longrun