# Deployment Guide - Supervisor UI ## Environment Variables The Supervisor UI supports flexible configuration through environment variables that can be set at both build-time and runtime. ### Available Environment Variables | Variable | Description | Default | Required | |----------|-------------|---------|----------| | `SUPERVISOR_HOST` | Supervisor API host/IP address | `localhost` | Yes | | `SUPERVISOR_PORT` | Supervisor API port | `9001` | Yes | | `SUPERVISOR_USERNAME` | Basic auth username (if enabled) | - | No | | `SUPERVISOR_PASSWORD` | Basic auth password (if enabled) | - | No | | `NODE_ENV` | Node environment | `production` | No | | `PORT` | Application port | `3000` | No | ### Configuration Priority Environment variables can be set at different stages, with runtime taking precedence: 1. **Runtime** (highest priority) - Docker run `-e` flags or docker-compose environment 2. **Build-time** - Docker build `--build-arg` flags 3. **Dockerfile defaults** (lowest priority) ## Docker Build Arguments You can customize the build with build arguments: ```bash docker build -t supervisor-ui \ --build-arg SUPERVISOR_HOST=supervisor.example.com \ --build-arg SUPERVISOR_PORT=9001 \ --build-arg SUPERVISOR_USERNAME=admin \ --build-arg SUPERVISOR_PASSWORD=secret \ . ``` **Note**: Build arguments are embedded in the image layer. For sensitive credentials, prefer runtime environment variables. ## Docker Runtime Configuration ### Option 1: Environment Variables via Docker Run ```bash docker run -d \ --name supervisor-ui \ -p 3000:3000 \ -e SUPERVISOR_HOST=supervisor.example.com \ -e SUPERVISOR_PORT=9001 \ -e SUPERVISOR_USERNAME=admin \ -e SUPERVISOR_PASSWORD=secret \ dev.pivoine.art/valknar/supervisor-ui:latest ``` ### Option 2: Environment File Create an `.env` file: ```env SUPERVISOR_HOST=supervisor.example.com SUPERVISOR_PORT=9001 SUPERVISOR_USERNAME=admin SUPERVISOR_PASSWORD=secret ``` Run with env file: ```bash docker run -d \ --name supervisor-ui \ -p 3000:3000 \ --env-file .env \ dev.pivoine.art/valknar/supervisor-ui:latest ``` ### Option 3: Docker Compose Create a `.env` file in the same directory as `docker-compose.yml`: ```env SUPERVISOR_HOST=supervisor.example.com SUPERVISOR_PORT=9001 SUPERVISOR_USERNAME=admin SUPERVISOR_PASSWORD=secret ``` The `docker-compose.yml` automatically picks up these variables: ```bash docker-compose up -d ``` ### Option 4: Docker Compose with Inline Environment Edit `docker-compose.yml`: ```yaml services: supervisor-ui: image: dev.pivoine.art/valknar/supervisor-ui:latest environment: - SUPERVISOR_HOST=supervisor.example.com - SUPERVISOR_PORT=9001 - SUPERVISOR_USERNAME=admin - SUPERVISOR_PASSWORD=secret ``` ## CI/CD - Gitea Workflows ### Automatic Builds The project includes a Gitea Actions workflow that automatically builds and pushes Docker images to the Gitea registry. **Workflow file**: `.gitea/workflows/docker-build-push.yml` ### Trigger Events Images are built and pushed on: 1. **Push to main branch** → Tagged as `latest` and `main-` 2. **Push to develop branch** → Tagged as `develop` and `develop-` 3. **Git tags** (v*.*.* pattern) → Tagged as version (e.g., `v1.0.0`, `1.0`, `1`) 4. **Pull requests** → Built but not pushed (validation only) 5. **Manual workflow dispatch** → Custom tag specified by user ### Workflow Secrets The workflow requires one secret to be configured in your Gitea repository: - `REGISTRY_TOKEN` - Gitea personal access token with registry push permissions #### Creating the Registry Token 1. Go to Gitea Settings → Applications → Generate New Token 2. Name: `GitHub Actions Registry` 3. Select scope: `write:package` 4. Copy the generated token 5. Go to Repository Settings → Secrets → Add Secret 6. Name: `REGISTRY_TOKEN` 7. Value: Paste the token ### Registry Authentication To pull images from the Gitea registry: ```bash # Login to registry docker login dev.pivoine.art # Pull image docker pull dev.pivoine.art/valknar/supervisor-ui:latest ``` ### Image Tags After pushing to main, the following tags are available: ```bash # Latest stable dev.pivoine.art/valknar/supervisor-ui:latest # Specific commit dev.pivoine.art/valknar/supervisor-ui:main-abc1234 # Version tags (from git tags) dev.pivoine.art/valknar/supervisor-ui:v1.0.0 dev.pivoine.art/valknar/supervisor-ui:1.0 dev.pivoine.art/valknar/supervisor-ui:1 # Development branch dev.pivoine.art/valknar/supervisor-ui:develop ``` ## Production Deployment Scenarios ### Scenario 1: Supervisor on Same Host Deploy UI on the same host as Supervisor: ```bash docker run -d \ --name supervisor-ui \ --network host \ -e SUPERVISOR_HOST=localhost \ -e SUPERVISOR_PORT=9001 \ dev.pivoine.art/valknar/supervisor-ui:latest ``` Using `--network host` allows the container to access localhost services. ### Scenario 2: Supervisor on Different Host Deploy UI on a different host: ```bash docker run -d \ --name supervisor-ui \ -p 3000:3000 \ -e SUPERVISOR_HOST=192.168.1.100 \ -e SUPERVISOR_PORT=9001 \ dev.pivoine.art/valknar/supervisor-ui:latest ``` Ensure the Supervisor inet_http_server is accessible from the UI host (not bound to 127.0.0.1). ### Scenario 3: Multiple Supervisor Instances (Future) While the current version connects to a single instance, you can run multiple UI containers: ```bash # Production Supervisor UI docker run -d \ --name supervisor-ui-prod \ -p 3000:3000 \ -e SUPERVISOR_HOST=prod.supervisor.local \ dev.pivoine.art/valknar/supervisor-ui:latest # Staging Supervisor UI docker run -d \ --name supervisor-ui-staging \ -p 3001:3000 \ -e SUPERVISOR_HOST=staging.supervisor.local \ dev.pivoine.art/valknar/supervisor-ui:latest ``` ### Scenario 4: Behind Reverse Proxy (nginx/Traefik) Example nginx configuration: ```nginx server { listen 80; server_name supervisor.example.com; location / { proxy_pass http://localhost:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` Example Traefik docker-compose labels: ```yaml services: supervisor-ui: image: dev.pivoine.art/valknar/supervisor-ui:latest environment: - SUPERVISOR_HOST=supervisor.local - SUPERVISOR_PORT=9001 labels: - "traefik.enable=true" - "traefik.http.routers.supervisor-ui.rule=Host(`supervisor.example.com`)" - "traefik.http.routers.supervisor-ui.entrypoints=websecure" - "traefik.http.routers.supervisor-ui.tls.certresolver=letsencrypt" - "traefik.http.services.supervisor-ui.loadbalancer.server.port=3000" ``` ### Scenario 5: Docker Compose Stack Complete production-ready stack with reverse proxy: ```yaml version: '3.8' services: supervisor-ui: image: dev.pivoine.art/valknar/supervisor-ui:latest container_name: supervisor-ui restart: unless-stopped environment: - SUPERVISOR_HOST=${SUPERVISOR_HOST} - SUPERVISOR_PORT=${SUPERVISOR_PORT} - SUPERVISOR_USERNAME=${SUPERVISOR_USERNAME} - SUPERVISOR_PASSWORD=${SUPERVISOR_PASSWORD} networks: - supervisor-network healthcheck: test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] interval: 30s timeout: 10s retries: 3 start_period: 5s labels: - "traefik.enable=true" - "traefik.http.routers.supervisor-ui.rule=Host(`supervisor.yourdomain.com`)" - "traefik.http.services.supervisor-ui.loadbalancer.server.port=3000" networks: supervisor-network: external: true ``` ## Security Considerations ### 1. Credentials Management **Bad** (credentials in image): ```bash docker build --build-arg SUPERVISOR_PASSWORD=secret . ``` **Good** (credentials at runtime): ```bash docker run -e SUPERVISOR_PASSWORD=secret ... ``` **Better** (use secrets management): ```bash # Docker Swarm secrets echo "secret_password" | docker secret create supervisor_password - ``` ### 2. Network Isolation Use Docker networks to isolate services: ```yaml services: supervisor-ui: networks: - internal # Only accessible from other containers nginx: networks: - internal - public # Exposed to internet ``` ### 3. Read-only Filesystem For enhanced security, run with read-only root filesystem: ```bash docker run -d \ --read-only \ --tmpfs /tmp \ -e SUPERVISOR_HOST=supervisor.local \ dev.pivoine.art/valknar/supervisor-ui:latest ``` ### 4. Resource Limits Prevent resource exhaustion: ```yaml services: supervisor-ui: deploy: resources: limits: cpus: '0.5' memory: 256M reservations: cpus: '0.25' memory: 128M ``` ## Monitoring & Health Checks ### Health Check Endpoint The application provides a health check at `/api/health`: ```bash curl http://localhost:3000/api/health # {"status":"healthy","timestamp":"2025-11-23T17:00:00.000Z"} ``` ### Docker Health Check Built-in health check monitors the API: ```bash docker inspect supervisor-ui --format='{{.State.Health.Status}}' ``` ### Integration with Monitoring Tools #### Prometheus Add health check as a target in `prometheus.yml`: ```yaml scrape_configs: - job_name: 'supervisor-ui' metrics_path: '/api/health' static_configs: - targets: ['supervisor-ui:3000'] ``` #### Uptime Kuma Add HTTP(s) monitor: - Monitor Type: HTTP(s) - URL: `http://supervisor-ui:3000/api/health` - Interval: 60 seconds ## Troubleshooting ### Container won't start Check logs: ```bash docker logs supervisor-ui ``` Common issues: - Port 3000 already in use - Invalid environment variables - Network connectivity issues ### Can't connect to Supervisor 1. Check if Supervisor is accessible: ```bash # From host curl http://supervisor-host:9001/RPC2 # From container docker exec supervisor-ui curl http://supervisor-host:9001/RPC2 ``` 2. Verify Supervisor configuration in `/etc/supervisor/supervisord.conf`: ```ini [inet_http_server] port = *:9001 ; Listen on all interfaces, not just 127.0.0.1 ``` 3. Check environment variables: ```bash docker exec supervisor-ui env | grep SUPERVISOR ``` ### Authentication failures Verify credentials match your Supervisor configuration: ```bash # Test with curl curl -u username:password http://supervisor-host:9001/RPC2 ``` ## Rollback Strategy ### Quick Rollback to Previous Version ```bash # Stop current version docker stop supervisor-ui docker rm supervisor-ui # Run previous version docker run -d \ --name supervisor-ui \ -p 3000:3000 \ --env-file .env \ dev.pivoine.art/valknar/supervisor-ui:v1.0.0 # Specific version ``` ### Using Docker Compose ```bash # Edit docker-compose.yml to use previous tag # Then: docker-compose up -d --force-recreate ``` ## Backup & Recovery ### No Persistent Data The Supervisor UI is stateless and doesn't store any data. All configuration is in environment variables. To "backup" your deployment: 1. Save your `.env` file or docker-compose.yml 2. Document your Supervisor connection details To "restore": 1. Pull the image 2. Apply your saved environment configuration 3. Start the container ## Performance Tuning ### Node.js Optimization For better performance in production: ```bash docker run -d \ -e NODE_OPTIONS="--max-old-space-size=256" \ -e SUPERVISOR_HOST=supervisor.local \ dev.pivoine.art/valknar/supervisor-ui:latest ``` ### Caching Strategies The application uses React Query with intelligent caching: - System info: 5 second stale time - Processes: 3 second stale time - Logs: 2 second stale time These are optimized for real-time monitoring while minimizing API calls. ## Scaling Considerations ### Horizontal Scaling The application is stateless and can be scaled horizontally: ```yaml services: supervisor-ui: image: dev.pivoine.art/valknar/supervisor-ui:latest deploy: replicas: 3 update_config: parallelism: 1 delay: 10s restart_policy: condition: on-failure ``` ### Load Balancing Use nginx or Traefik to load balance across replicas: ```nginx upstream supervisor_ui { server supervisor-ui-1:3000; server supervisor-ui-2:3000; server supervisor-ui-3:3000; } server { location / { proxy_pass http://supervisor_ui; } } ``` --- **Last Updated**: November 23, 2025 **Version**: 0.1.0