OW / Dockerfile
Alexander Vinokur
Fix: remove only the extra fi after config load
42c2605
FROM node:22-slim
# Install system dependencies including Chromium for browser support
RUN apt-get update && apt-get install -y \
git \
bash \
curl \
jq \
python3 \
python3-pip \
python3-venv \
chromium \
chromium-driver \
fonts-liberation \
libasound2 \
libatk-bridge2.0-0 \
libatk1.0-0 \
libatspi2.0-0 \
libcups2 \
libdbus-1-3 \
libdrm2 \
libgbm1 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libwayland-client0 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxkbcommon0 \
libxrandr2 \
xdg-utils \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g openclaw@latest
# Create Python virtual environment and install PostgreSQL driver
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
RUN pip install --no-cache-dir psycopg2-binary
RUN mkdir -p /root/.openclaw
EXPOSE 18789
# Python script for DB operations with Neon support
RUN cat > /usr/local/bin/db-manager.py << 'PYSCRIPT'
#!/usr/bin/env python3
import psycopg2
import json
import sys
import os
def get_connection():
# Use DATABASE_URL if provided (Neon), otherwise use individual params
database_url = os.environ.get('DATABASE_URL')
if database_url:
return psycopg2.connect(database_url)
else:
return psycopg2.connect(
host=os.environ.get('POSTGRES_HOST', 'localhost'),
port=os.environ.get('POSTGRES_PORT', '5432'),
database=os.environ.get('POSTGRES_DB', 'openclaw_db'),
user=os.environ.get('POSTGRES_USER', 'openclaw'),
password=os.environ.get('POSTGRES_PASSWORD')
)
def load_config():
"""Load OpenClaw config from PostgreSQL"""
try:
conn = get_connection()
cur = conn.cursor()
cur.execute("SELECT config_value FROM openclaw_config WHERE config_key = 'openclaw_main'")
row = cur.fetchone()
cur.close()
conn.close()
if row:
return row[0]
return None
except Exception as e:
print(f"Error loading config from DB: {e}", file=sys.stderr)
return None
def save_config(config_json):
"""Save OpenClaw config to PostgreSQL"""
try:
conn = get_connection()
cur = conn.cursor()
cur.execute("""
INSERT INTO openclaw_config (config_key, config_value, updated_at)
VALUES ('openclaw_main', %s::jsonb, CURRENT_TIMESTAMP)
ON CONFLICT (config_key)
DO UPDATE SET config_value = EXCLUDED.config_value, updated_at = CURRENT_TIMESTAMP
""", (config_json,))
conn.commit()
cur.close()
conn.close()
return True
except Exception as e:
print(f"Error saving config to DB: {e}", file=sys.stderr)
return False
def init_db():
"""Initialize database with default config if not exists"""
try:
conn = get_connection()
cur = conn.cursor()
cur.execute("SELECT COUNT(*) FROM openclaw_config WHERE config_key = 'openclaw_main'")
count = cur.fetchone()[0]
cur.close()
conn.close()
return count > 0
except Exception as e:
print(f"Error checking DB: {e}", file=sys.stderr)
return False
if __name__ == '__main__':
action = sys.argv[1] if len(sys.argv) > 1 else 'load'
if action == 'load':
config = load_config()
if config:
print(json.dumps(config))
else:
sys.exit(1)
elif action == 'save':
config_json = sys.stdin.read()
if save_config(config_json):
sys.exit(0)
else:
sys.exit(1)
elif action == 'init':
if init_db():
print("DB already initialized")
else:
print("DB not initialized")
sys.exit(1)
PYSCRIPT
RUN chmod +x /usr/local/bin/db-manager.py
# Config sync daemon
RUN cat > /usr/local/bin/sync-config.sh << 'SYNCSCRIPT'
#!/bin/bash
CONFIG_FILE="/root/.openclaw/openclaw.json"
LAST_HASH=""
echo "[sync-daemon] Config sync daemon started"
sleep 10
while true; do
if [ -f "$CONFIG_FILE" ]; then
CURRENT_HASH=$(md5sum "$CONFIG_FILE" | awk '{print $1}')
if [ "$CURRENT_HASH" != "$LAST_HASH" ] && [ -n "$LAST_HASH" ]; then
echo "[sync-daemon] Config changed detected, syncing to DB..."
if cat "$CONFIG_FILE" | /opt/venv/bin/python3 /usr/local/bin/db-manager.py save; then
echo "[sync-daemon] ��� Config synced at $(date -Iseconds)"
else
echo "[sync-daemon] ��� Failed to sync config"
fi
fi
LAST_HASH="$CURRENT_HASH"
fi
sleep 30
done
SYNCSCRIPT
RUN cat > /usr/local/bin/start-openclaw.sh << 'SCRIPT'
#!/bin/bash
set -e
echo "=== OpenClaw Startup with Browser Support ==="
if [ -z "$OPENCLAW_GATEWAY_PASSWORD" ]; then
echo "ERROR: OPENCLAW_GATEWAY_PASSWORD not set!"
exit 1
fi
if [ -z "$KIRO_API_KEY" ]; then
echo "ERROR: KIRO_API_KEY not set!"
exit 1
fi
if [ -z "$DATABASE_URL" ]; then
echo "ERROR: DATABASE_URL not set!"
exit 1
fi
if [ -n "$TELEGRAM_STEVE_TOKEN" ]; then
echo "Telegram Steve bot token found"
fi
if [ -n "$TELEGRAM_DEN_TOKEN" ]; then
echo "Telegram Den bot token found"
fi
if [ -n "$TELEGRAM_OLYA_TOKEN" ]; then
echo "Telegram Olya bot token found"
fi
if [ -n "$SPACE_HOST" ]; then
ALLOWED_ORIGIN="https://${SPACE_HOST}"
else
ALLOWED_ORIGIN="*"
fi
echo "Loading config from Neon PostgreSQL..."
if ! /opt/venv/bin/python3 /usr/local/bin/db-manager.py load > /root/.openclaw/openclaw.json; then
echo "ERROR: Failed to load config from Neon DB!"
echo "Please ensure config exists in openclaw_config table with key 'openclaw_main'"
exit 1
fi
echo "��� Config loaded successfully from Neon"
chmod 700 /root/.openclaw
chmod 600 /root/.openclaw/openclaw.json
echo "Starting config sync daemon..."
/usr/local/bin/sync-config.sh &
echo "��� Sync daemon started (PID: $!)"
echo "Starting OpenClaw Gateway with browser support..."
exec openclaw gateway run --port 18789
SCRIPT
RUN chmod +x /usr/local/bin/start-openclaw.sh
RUN chmod +x /usr/local/bin/sync-config.sh
CMD ["/usr/local/bin/start-openclaw.sh"]