# Portainer Deployment Guide ## Overview This guide covers deploying Mosaic Stack via Portainer. Portainer has specific requirements that differ from standard docker-compose deployments. ## Key Differences **Portainer Limitations:** - ❌ Does NOT support `env_file:` directive - ❌ Does NOT support localhost-only port bindings (`127.0.0.1:port`) - ❌ Does NOT support health check conditions in `depends_on` - ✅ DOES support environment variables defined in Portainer UI - ✅ DOES support external networks **Solution:** Use `docker-compose.portainer.yml` which is optimized for Portainer. ## Prerequisites ### 1. Create Overlay Network **In Portainer:** 1. Go to **Networks** → **Add network** 2. Name: `mosaic_internal` 3. Driver: `overlay` 4. Enable **Attachable** 5. Click **Create network** **Or via CLI:** ```bash docker network create --driver=overlay --attachable mosaic_internal ``` ### 2. Registry Authentication If using private registry images from `git.mosaicstack.dev`: **In Portainer:** 1. Go to **Registries** → **Add registry** 2. Type: **Custom Registry** 3. Name: `Gitea Mosaic` 4. Registry URL: `git.mosaicstack.dev` 5. Username: Your Gitea username 6. Password: Your Gitea password or access token 7. Click **Add registry** ## Deployment Steps ### Step 1: Deploy OpenBao Stack **Why First?** OpenBao must be running before the main stack starts, as the API needs to connect to it. **In Portainer:** 1. Go to **Stacks** → **Add stack** 2. **Name:** `mosaic-openbao` 3. **Build method:** Web editor 4. **Web editor:** Copy and paste contents of `docker-compose.portainer.yml` 5. **Environment variables:** ``` IMAGE_TAG=dev OPENBAO_PORT=8200 ``` 6. Click **Deploy the stack** **Verify Deployment:** 1. Go to **Stacks** → `mosaic-openbao` 2. Check both containers are running: - `mosaic-openbao` (should be running) - `mosaic-openbao-init` (will stop after initialization) 3. View logs: - Click on `mosaic-openbao-init` → **Logs** - Look for: `✓ OpenBao initialized successfully` **Wait 30 seconds** for initialization to complete before proceeding. ### Step 2: Deploy Swarm Stack **In Portainer:** 1. Go to **Stacks** → **Add stack** 2. **Name:** `mosaic` 3. **Build method:** Repository (recommended) or Web editor **Option A: Git Repository (Recommended)** - Repository URL: `https://git.mosaicstack.dev/mosaic/stack` - Repository reference: `refs/heads/develop` - Compose path: `docker-compose.swarm.yml` - Authentication: Enable if repository is private - Enable **Automatic updates** (optional) - Update interval: `5m` (checks every 5 minutes) **Option B: Web Editor** - Copy and paste contents of `docker-compose.swarm.yml` 4. **Environment variables:** ``` IMAGE_TAG=dev POSTGRES_PASSWORD= JWT_SECRET= BETTER_AUTH_SECRET= ENCRYPTION_KEY= OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_ISSUER=https://auth.diversecanvas.com/application/o/mosaic-stack/ OIDC_REDIRECT_URI=https://api.mosaicstack.dev/auth/oauth2/callback/authentik OLLAMA_ENDPOINT=http://10.1.1.42:11434 ``` 5. Click **Deploy the stack** ### Step 3: Verify Deployment **Check Services:** 1. Go to **Swarm** → **Services** 2. Verify all services show `1/1` replicas: - `mosaic_postgres` - `mosaic_valkey` - `mosaic_api` - `mosaic_web` - `mosaic_orchestrator` **Check Logs:** 1. Go to **Swarm** → **Services** → `mosaic_api` 2. Click on the running task 3. Click **Logs** 4. Look for: `OpenBao connection established` or `Using fallback encryption` **Access Services:** - Web UI: http://app.mosaicstack.dev - API: http://api.mosaicstack.dev/health - OpenBao: http://:8200/ui ## Environment Variables Reference ### Required for All Deployments ```bash # Image Configuration IMAGE_TAG=dev # or 'latest' or specific commit SHA # Database POSTGRES_PASSWORD= DATABASE_URL=postgresql://mosaic:${POSTGRES_PASSWORD}@postgres:5432/mosaic # Security JWT_SECRET= # openssl rand -base64 32 BETTER_AUTH_SECRET= ENCRYPTION_KEY=<64-char-hex> # openssl rand -hex 32 # External OIDC (Authentik) OIDC_CLIENT_ID= OIDC_CLIENT_SECRET= OIDC_ISSUER=https://auth.diversecanvas.com/application/o/mosaic-stack/ OIDC_REDIRECT_URI=https://api.mosaicstack.dev/auth/oauth2/callback/authentik # External Ollama OLLAMA_ENDPOINT=http://10.1.1.42:11434 ``` ### Optional Variables ```bash # Ports OPENBAO_PORT=8200 API_PORT=3001 WEB_PORT=3000 # Cache VALKEY_MAXMEMORY=256mb # Logging LOG_LEVEL=info DEBUG=false ``` ## Updating Stacks ### Update OpenBao 1. Go to **Stacks** → `mosaic-openbao` 2. Click **Editor** 3. Update `IMAGE_TAG` environment variable (or compose file) 4. Click **Update the stack** 5. Enable **Re-pull image** 6. Click **Update** ### Update Swarm Stack **If using Git Repository:** - Portainer automatically pulls updates based on update interval - Or manually: **Stacks** → `mosaic` → **Pull and redeploy** **If using Web Editor:** 1. Go to **Stacks** → `mosaic` 2. Click **Editor** 3. Update compose file or environment variables 4. Click **Update the stack** 5. Enable **Re-pull images** 6. Click **Update** ## Troubleshooting ### Stack Deployment Failed: "network not found" **Cause:** `mosaic_internal` network doesn't exist **Fix:** ```bash docker network create --driver=overlay --attachable mosaic_internal ``` ### OpenBao Unhealthy **Check logs:** 1. **Containers** → `mosaic-openbao` → **Logs** 2. Look for errors **Common issues:** - Port 8200 already in use → Stop conflicting service - Config file not found → Rebuild image - Permission denied → Check volume permissions ### API Can't Connect to OpenBao **Symptoms:** - API logs show "connection refused" to OpenBao - API falls back to encryption key **Check:** 1. **Containers** → `mosaic-openbao` → Verify it's running 2. **Networks** → `mosaic_internal` → Verify both stacks are connected 3. API environment: `OPENBAO_ADDR=http://openbao:8200` **Test connectivity:** 1. **Containers** → Find API container → **Console** 2. Run: `wget -qO- http://openbao:8200/v1/sys/health` ### Services Not Starting in Swarm Stack **Check service logs:** 1. **Swarm** → **Services** → Click service 2. Click running/failed task 3. View logs **Common issues:** - Missing environment variables - Image pull failed (check registry authentication) - Dependency not ready (database, OpenBao) ## Best Practices ### Security 1. **Never expose OpenBao to public internet** without TLS 2. **Use firewall rules** to restrict port 8200 access 3. **Rotate secrets regularly** (JWT_SECRET, API keys) 4. **Use strong passwords** for PostgreSQL 5. **Enable TLS** for production deployments ### Monitoring **In Portainer:** 1. **Dashboard** → View resource usage 2. **Stacks** → Monitor stack health 3. **Swarm** → **Services** → Monitor replicas **Set up alerts:** 1. **Notifications** → Configure webhook/email 2. **Events** → Enable service alerts ### Backups **OpenBao Volumes:** ```bash # Backup docker run --rm \ -v mosaic-openbao-data:/data \ -v $(pwd):/backup \ alpine tar czf /backup/openbao-$(date +%Y%m%d).tar.gz -C /data . # Restore docker run --rm \ -v mosaic-openbao-data:/data \ -v $(pwd):/backup \ alpine sh -c 'rm -rf /data/* && tar xzf /backup/openbao-20260208.tar.gz -C /data' ``` **PostgreSQL:** ```bash # Backup docker exec mosaic_postgres pg_dump -U mosaic mosaic > backup.sql # Restore docker exec -i mosaic_postgres psql -U mosaic mosaic < backup.sql ``` ## Advanced Configuration ### Using External Services To use external PostgreSQL, Valkey, or Vault: 1. Edit `docker-compose.swarm.yml` in Portainer 2. Comment out the service you want to replace 3. Update environment variables to point to external service 4. Update the stack **Example - External PostgreSQL:** ```yaml # Comment out postgres service # postgres: # ... # Update API environment services: api: environment: DATABASE_URL: postgresql://user:pass@external-db.example.com:5432/mosaic ``` ### Custom Domains Update environment variables: ```bash NEXT_PUBLIC_APP_URL=https://mosaic.example.com NEXT_PUBLIC_API_URL=https://api.example.com OIDC_REDIRECT_URI=https://api.example.com/auth/oauth2/callback/authentik ``` ### Resource Limits Add to services in Portainer editor: ```yaml services: api: deploy: resources: limits: cpus: "1" memory: 1G reservations: cpus: "0.5" memory: 512M ``` ## See Also - [Swarm Deployment Guide](SWARM-DEPLOYMENT.md) - CLI-based deployment - [OpenBao Deployment Guide](OPENBAO-DEPLOYMENT.md) - OpenBao options - [Configuration Guide](CONFIGURATION.md) - All environment variables - [Docker Compose Guide](../docker/DOCKER-COMPOSE-GUIDE.md) - Standalone deployment