- Add API endpoint and curl commands to check CI status - Document authentication with Authorization: token header - Add response field descriptions (status, conclusion) - Reference BWS key for GITEA_API_TOKEN
AI Stack Deployer
NEVER FORGET THE PRINCIPLES RULES
Self-service portal for deploying personal OpenCode AI coding assistant stacks
Overview
AI Stack Deployer is a production-ready web application that allows users to deploy their own personal AI coding assistant in seconds. Each deployment creates a fully functional OpenCode instance at {name}.ai.flexinit.nl with automatic HTTPS via wildcard SSL certificate.
Key Features
- One-Click Deployment: Deploy AI stacks with a single form submission
- Real-Time Progress: SSE-powered live updates during deployment
- Name Validation: Real-time availability checking and format validation
- Modern UI: Responsive design with smooth animations
- Production Ready: Docker containerized with health checks
- No DNS Setup: Leverages pre-configured wildcard DNS and SSL
Architecture
User Browser
↓
AI Stack Deployer (Hono + Bun)
↓
Dokploy API (10.100.0.20:3000)
↓
Traefik (*.ai.flexinit.nl → 144.76.116.169)
↓
User's AI Stack Container (OpenCode + ttyd)
Technology Stack
- Runtime: Bun 1.3+
- Framework: Hono 4.11.3
- Language: TypeScript
- Container: Docker with multi-stage builds
- Orchestration: Dokploy
- Reverse Proxy: Traefik with wildcard SSL
Quick Start
Prerequisites
- Bun 1.3 or higher
- Docker (for containerized deployment)
- Valid Dokploy API token
- Access to Dokploy instance at
http://10.100.0.20:3000
Local Development
-
Clone and Install:
git clone <repository-url> cd ai-stack-deployer bun install -
Configure Environment:
cp .env.example .env # Edit .env and add your DOKPLOY_API_TOKEN -
Run Development Server:
bun run dev -
Access the Application: Open http://localhost:3000 in your browser
Production Deployment
Option 1: Docker Compose (Recommended)
# Build and run
docker-compose up -d
# View logs
docker-compose logs -f
# Stop
docker-compose down
Option 2: Manual Docker
# Build
docker build -t ai-stack-deployer:latest .
# Run
docker run -d \
--name ai-stack-deployer \
-p 3000:3000 \
--env-file .env \
ai-stack-deployer:latest
# Check health
curl http://localhost:3000/health
Option 3: Deploy to Dokploy
-
Build and push to registry:
docker build -t your-registry/ai-stack-deployer:latest . docker push your-registry/ai-stack-deployer:latest -
In Dokploy UI:
- Create project:
ai-stack-deployer-portal - Create application from Docker image
- Set domain:
portal.ai.flexinit.nl - Configure environment variables
- Deploy
- Create project:
-
Verify:
curl https://portal.ai.flexinit.nl/health
API Documentation
Endpoints
Health Check
GET /health
Response:
{
"status": "healthy",
"timestamp": "2026-01-09T12:00:00.000Z",
"version": "0.1.0",
"service": "ai-stack-deployer",
"activeDeployments": 0
}
Check Name Availability
GET /api/check/:name
Response:
{
"available": true,
"valid": true,
"name": "john-dev"
}
Deploy Stack
POST /api/deploy
Content-Type: application/json
{
"name": "john-dev"
}
Response:
{
"success": true,
"deploymentId": "dep_1234567890_abc123",
"url": "https://john-dev.ai.flexinit.nl",
"statusEndpoint": "/api/status/dep_1234567890_abc123"
}
Deployment Status (SSE)
GET /api/status/:deploymentId
Server-Sent Events stream with progress updates:
event: progress
data: {"status":"creating_project","progress":25,"currentStep":"Creating Dokploy project"}
event: progress
data: {"status":"creating_application","progress":50,"currentStep":"Creating application container"}
event: progress
data: {"status":"deploying","progress":85,"currentStep":"Deploying application"}
event: complete
data: {"url":"https://john-dev.ai.flexinit.nl","status":"ready"}
Environment Variables
Required
DOKPLOY_URL- Dokploy API URL (default:http://10.100.0.20:3000)DOKPLOY_API_TOKEN- Dokploy API authentication token
Optional
PORT- HTTP server port (default:3000)HOST- Bind address (default:0.0.0.0)STACK_DOMAIN_SUFFIX- Domain suffix for stacks (default:ai.flexinit.nl)STACK_IMAGE- Docker image for user stacks (default:git.app.flexinit.nl/oussamadouhou/oh-my-opencode-free:latest)RESERVED_NAMES- Comma-separated forbidden names (default:admin,api,www,root,system,test,demo,portal)
Not Used in Deployment
HETZNER_API_TOKEN- Only for testing/manual DNS operationsHETZNER_ZONE_ID- DNS zone ID (343733 for flexinit.nl)TRAEFIK_IP- Public IP reference (144.76.116.169)
Name Validation Rules
Stack names must follow these rules:
- 3-20 characters long
- Lowercase letters (a-z), numbers (0-9), and hyphens (-) only
- Cannot start or end with a hyphen
- Cannot be a reserved name (admin, api, www, root, system, test, demo, portal)
Development
Commands
# Development server with hot reload
bun run dev
# Production server
bun run start
# MCP server (for Claude Code integration)
bun run mcp
# Type checking
bun run typecheck
# Build for production
bun run build
# Test API clients
bun run src/test-clients.ts
Project Structure
ai-stack-deployer/
├── src/
│ ├── api/
│ │ ├── dokploy.ts # Dokploy API client
│ │ └── hetzner.ts # Hetzner DNS client (testing only)
│ ├── frontend/
│ │ ├── index.html # Web UI
│ │ ├── style.css # Styles
│ │ └── app.js # Frontend logic
│ ├── index.ts # HTTP server (production)
│ ├── mcp-server.ts # MCP server (development)
│ └── test-clients.ts # API client tests
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Docker Compose configuration
├── .dockerignore # Docker build exclusions
├── CLAUDE.md # Claude Code guidance
└── README.md # This file
MCP Server (Development Tool)
The MCP server provides Claude Code integration for deployment automation:
# Start MCP server
bun run mcp
Available MCP tools:
deploy_stack- Deploy a new AI stackcheck_deployment_status- Query deployment progresslist_deployments- List all deploymentscheck_name_availability- Validate stack nametest_api_connections- Test Dokploy connectivity
Infrastructure Requirements
Pre-configured Components
- Wildcard DNS:
*.ai.flexinit.nl→144.76.116.169 - Traefik: Wildcard SSL certificate for
*.ai.flexinit.nl - Dokploy: Running at
http://10.100.0.20:3000 - OpenCode Image:
git.app.flexinit.nl/oussamadouhou/oh-my-opencode-free:latest
Network Access
The deployer must be able to reach:
- Dokploy API at
10.100.0.20:3000(internal network) - No public internet access required for deployment
- Frontend users connect via Traefik at
144.76.116.169
Troubleshooting
Health Check Failing
# Check if server is running
curl http://localhost:3000/health
# Check Docker logs
docker-compose logs -f ai-stack-deployer
# Restart container
docker-compose restart
Deployment Stuck
-
Check Dokploy API connectivity:
curl -H "x-api-key: YOUR_TOKEN" http://10.100.0.20:3000/api/project.all -
View deployment logs in browser console (F12)
-
Check server logs for errors:
docker-compose logs -f | grep ERROR
Name Already Taken
If a deployment fails but the name is marked as taken:
- Check Dokploy UI for the project
ai-stack-{name} - Delete the partial deployment if present
- Try deployment again
Security Notes
- All API tokens stored in environment variables (never in code)
- Dokploy API accessible only on internal network
- No authentication on HTTP endpoints (add if exposing publicly)
- Name validation prevents injection attacks
- Container runs as non-root user (nodejs:1001)
Performance
- Deployment Time: ~2-3 minutes per stack
- Concurrent Deployments: No limit (background processing)
- Memory Usage: ~50MB base + ~10MB per active deployment
- State Persistence: In-memory only (implement database for persistence)
Contributing
See CLAUDE.md for development guidelines and architecture documentation.
License
[Your License Here]
Support
For issues or questions:
- Check the troubleshooting section above
- Review logs:
docker-compose logs -f - Verify environment variables in
.env
Built with ❤️ using Bun, Hono, and Dokploy