- Add multi-language support (NL, AR, EN) with RTL
- Improve health checks (SSL-tolerant, multi-endpoint)
- Add DELETE /api/stack/:name for cleanup
- Add persistent storage (portal-ai-workspace-{name})
- Improve rollback (delete domain, app, project)
- Increase SSE timeout to 255s
- Add deployment strategy documentation
8.3 KiB
AI Stack Deployer - Deployment Strategy
Overview
Deploy the AI Stack Deployer portal to production, making it accessible at deploy.ai.flexinit.nl.
User Stack Container (oh-my-opencode-free)
Image Details
| Property | Value |
|---|---|
| Registry | git.app.flexinit.nl |
| Image | oussamadouhou/oh-my-opencode-free:latest |
| Base | oven/bun:debian |
| Port | 8080 (OpenCode server) |
| CI/CD | Gitea Actions (auto-build on push) |
Pre-configured Free Models
| Agent | Model | Purpose |
|---|---|---|
| Sisyphus (main) | glm-4.7-free |
Primary coding |
| Oracle | gpt-5-nano |
Architecture |
| Librarian | minimax-m2.1-free |
Documentation |
| Explore | grok-code |
Codebase search |
| Frontend | glm-4.7-free |
UI/UX |
| Document Writer | gpt-5-nano |
Docs |
Baked Configuration
/shared/config/
├── opencode.json # CLI config
├── opencode.jsonc # Permissions
└── oh-my-opencode.json # Agent model assignments
Persistent Storage (per user)
| Volume | Mount Path | Purpose |
|---|---|---|
workspace-{name} |
/workspace |
User projects |
Architecture
Internet
│
▼
┌─────────────────────────────────────────────┐
│ Traefik (144.76.116.169) │
│ - SSL termination (wildcard *.ai.flexinit.nl)│
│ - Routes deploy.ai.flexinit.nl → portal │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ AI Stack Deployer Container │
│ - Port 3000 │
│ - Needs access to 10.100.0.20 (Dokploy) │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Dokploy (10.100.0.20:3000) │
│ - Creates user stacks │
│ - Manages containers │
└─────────────────────────────────────────────┘
Deployment Options
Option A: Deploy via Dokploy (Recommended)
Pros: Self-service, consistent with stack deployments, automatic restarts Cons: Circular dependency (if Dokploy is down, can't redeploy)
Option B: Direct Docker on Traefik Host
Pros: Independent of Dokploy, simpler network (same host as Traefik) Cons: Manual management, no Dokploy UI
Option C: Separate VM with Docker Compose
Pros: Isolation, can use docker-compose.yml directly Cons: Extra VM, network routing complexity
Decision: Option A (Dokploy) - Eat our own dog food, leverage existing infrastructure.
Step-by-Step Deployment
Phase 1: Prepare Image
# 1. Build and tag image
docker build -t git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:latest .
# 2. Push to registry
docker push git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:latest
Phase 2: Create Dokploy Project
- Open Dokploy UI: https://app.flexinit.nl
- Create project:
ai-stack-deployer-portal - Create application:
- Name:
deployer - Type: Docker Image
- Image:
git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:latest
- Name:
Phase 3: Configure Environment
Set these environment variables in Dokploy:
| Variable | Value | Source |
|---|---|---|
NODE_ENV |
production |
Static |
PORT |
3000 |
Static |
HOST |
0.0.0.0 |
Static |
DOKPLOY_URL |
http://10.100.0.20:3000 |
Static |
DOKPLOY_API_TOKEN |
<token> |
BWS: 6b3618fc-ba02-49bc-bdc8-b3c9004087bc |
STACK_DOMAIN_SUFFIX |
ai.flexinit.nl |
Static |
STACK_IMAGE |
git.app.flexinit.nl/oussamadouhou/oh-my-opencode-free:latest |
Static |
RESERVED_NAMES |
admin,api,www,root,system,test,demo,portal,deploy |
Static |
Phase 4: Configure Domain
-
In Dokploy application settings, add domain:
- Host:
deploy.ai.flexinit.nl - HTTPS: Enabled
- Port: 3000
- Host:
-
DNS is already configured (wildcard
*.ai.flexinit.nl→ 144.76.116.169)
Phase 5: Deploy
- Click "Deploy" in Dokploy UI
- Wait for container to start (~30s)
- Verify health:
curl https://deploy.ai.flexinit.nl/health
Network Requirements
The deployer container MUST be able to reach:
10.100.0.20:3000- Dokploy API (internal network)
This works automatically when deployed via Dokploy since containers share the internal network.
Secrets Management
Using BWS
# Get Dokploy token
bws secret get 6b3618fc-ba02-49bc-bdc8-b3c9004087bc
# Set in Dokploy environment variables (manually or via API)
Rotation Strategy
- Generate new token in Dokploy UI
- Store in BWS
- Update environment variable in Dokploy
- Redeploy application
Monitoring
Health Checks
- Endpoint:
GET /health - Interval: 30 seconds
- Expected:
{"status":"healthy",...}
Alerting
Set up monitoring for:
- Health endpoint failures
- High error rates in deployment logs
- Circuit breaker state changes
Rollback Procedure
Quick Rollback
# Via Dokploy UI
1. Go to application → Deployments
2. Click "Rollback" on previous successful deployment
Manual Rollback
# Re-deploy previous image tag
docker pull git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:v0.1.0
# Update image in Dokploy and redeploy
CI/CD Pipeline (Future)
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push
run: |
docker build -t git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:${{ github.sha }} .
docker push git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:${{ github.sha }}
- name: Deploy via Dokploy API
run: |
curl -X POST "$DOKPLOY_URL/api/application.update" \
-H "x-api-key: $DOKPLOY_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"applicationId": "$APP_ID", "dockerImage": "...:${{ github.sha }}"}'
curl -X POST "$DOKPLOY_URL/api/application.deploy" \
-H "x-api-key: $DOKPLOY_API_TOKEN" \
-d '{"applicationId": "$APP_ID"}'
Pre-Deployment Checklist
- Docker image builds successfully:
docker build -t test . - TypeScript compiles:
bun run typecheck - Health endpoint works locally:
curl localhost:3000/health - Dokploy API token is valid
- Registry credentials configured
- Domain DNS resolves correctly
Post-Deployment Verification
# 1. Health check
curl https://deploy.ai.flexinit.nl/health
# 2. Name validation
curl https://deploy.ai.flexinit.nl/api/check/test-name
# 3. Frontend loads
curl -s https://deploy.ai.flexinit.nl | grep -q "AI Stack Deployer"
# 4. Full deployment test (optional)
curl -X POST https://deploy.ai.flexinit.nl/api/deploy \
-H "Content-Type: application/json" \
-d '{"name": "smoke-test"}'
# 5. Cleanup test
curl -X DELETE https://deploy.ai.flexinit.nl/api/stack/smoke-test
Security Considerations
- No public auth yet - Consider adding authentication for production
- Rate limiting - Not implemented, consider adding
- API token exposure - Stored in Dokploy env vars (encrypted at rest)
- Delete endpoint - Should require authentication in production
Estimated Timeline
| Phase | Duration | Notes |
|---|---|---|
| Image build & push | 5 min | Automated |
| Dokploy project setup | 10 min | One-time |
| Environment config | 5 min | One-time |
| Deployment | 2 min | Per deploy |
| Verification | 5 min | Per deploy |
| Total first deploy | ~30 min | |
| Subsequent deploys | ~10 min |
Next Steps
- Build and push Docker image
- Create Dokploy project and application
- Configure environment variables
- Add domain
- Deploy and verify
- Set up monitoring
- (Optional) Implement CI/CD