Files
supervisor-ui/DEPLOYMENT.md
Sebastian Krüger e0cfd371c0
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Failing after 1m22s
feat: initial commit - Supervisor UI with Next.js 16 and Tailwind CSS 4
- Modern web interface for Supervisor process management
- Built with Next.js 16 (App Router) and Tailwind CSS 4
- Full XML-RPC client implementation for Supervisor API
- Real-time process monitoring with auto-refresh
- Process control: start, stop, restart operations
- Modern dashboard with system status and statistics
- Dark/light theme with OKLCH color system
- Docker multi-stage build with runtime env var configuration
- Gitea CI/CD workflow for automated builds
- Comprehensive documentation (README, IMPLEMENTATION, DEPLOYMENT)

Features:
- Backend proxy pattern for secure API communication
- React Query for state management and caching
- TypeScript strict mode with Zod validation
- Responsive design with mobile support
- Health check endpoint for monitoring
- Non-root user security in Docker

Environment Variables:
- SUPERVISOR_HOST, SUPERVISOR_PORT
- SUPERVISOR_USERNAME, SUPERVISOR_PASSWORD (optional)
- Configurable at build-time and runtime

🤖 Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-23 18:23:51 +01:00

12 KiB

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:

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

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:

SUPERVISOR_HOST=supervisor.example.com
SUPERVISOR_PORT=9001
SUPERVISOR_USERNAME=admin
SUPERVISOR_PASSWORD=secret

Run with env file:

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:

SUPERVISOR_HOST=supervisor.example.com
SUPERVISOR_PORT=9001
SUPERVISOR_USERNAME=admin
SUPERVISOR_PASSWORD=secret

The docker-compose.yml automatically picks up these variables:

docker-compose up -d

Option 4: Docker Compose with Inline Environment

Edit docker-compose.yml:

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-<sha>
  2. Push to develop branch → Tagged as develop and develop-<sha>
  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:

# 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:

# 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:

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:

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:

# 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:

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:

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:

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):

docker build --build-arg SUPERVISOR_PASSWORD=secret .

Good (credentials at runtime):

docker run -e SUPERVISOR_PASSWORD=secret ...

Better (use secrets management):

# Docker Swarm secrets
echo "secret_password" | docker secret create supervisor_password -

2. Network Isolation

Use Docker networks to isolate services:

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:

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:

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:

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:

docker inspect supervisor-ui --format='{{.State.Health.Status}}'

Integration with Monitoring Tools

Prometheus

Add health check as a target in prometheus.yml:

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:

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:
# From host
curl http://supervisor-host:9001/RPC2

# From container
docker exec supervisor-ui curl http://supervisor-host:9001/RPC2
  1. Verify Supervisor configuration in /etc/supervisor/supervisord.conf:
[inet_http_server]
port = *:9001  ; Listen on all interfaces, not just 127.0.0.1
  1. Check environment variables:
docker exec supervisor-ui env | grep SUPERVISOR

Authentication failures

Verify credentials match your Supervisor configuration:

# Test with curl
curl -u username:password http://supervisor-host:9001/RPC2

Rollback Strategy

Quick Rollback to Previous Version

# 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

# 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:

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:

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:

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