Changes:
- Create Gitea workflow for ai-stack-deployer
- Trigger on main branch (default branch)
- Use oussamadouhou + REGISTRY_TOKEN for authentication
- Build from ./Dockerfile
This enables :latest tag creation via {{is_default_branch}}.
Tags created:
- git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:latest
- git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:<sha>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
379 lines
8.9 KiB
Markdown
379 lines
8.9 KiB
Markdown
# AI Stack Deployer
|
|
|
|
> Self-service portal for deploying personal OpenCode AI coding assistant stacks
|
|
|
|
[](https://dokploy.com)
|
|
[](https://bun.sh)
|
|
[](https://hono.dev)
|
|
|
|
## 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
|
|
|
|
1. **Clone and Install**:
|
|
```bash
|
|
git clone <repository-url>
|
|
cd ai-stack-deployer
|
|
bun install
|
|
```
|
|
|
|
2. **Configure Environment**:
|
|
```bash
|
|
cp .env.example .env
|
|
# Edit .env and add your DOKPLOY_API_TOKEN
|
|
```
|
|
|
|
3. **Run Development Server**:
|
|
```bash
|
|
bun run dev
|
|
```
|
|
|
|
4. **Access the Application**:
|
|
Open http://localhost:3000 in your browser
|
|
|
|
### Production Deployment
|
|
|
|
#### Option 1: Docker Compose (Recommended)
|
|
|
|
```bash
|
|
# Build and run
|
|
docker-compose up -d
|
|
|
|
# View logs
|
|
docker-compose logs -f
|
|
|
|
# Stop
|
|
docker-compose down
|
|
```
|
|
|
|
#### Option 2: Manual Docker
|
|
|
|
```bash
|
|
# 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
|
|
|
|
1. Build and push to registry:
|
|
```bash
|
|
docker build -t your-registry/ai-stack-deployer:latest .
|
|
docker push your-registry/ai-stack-deployer:latest
|
|
```
|
|
|
|
2. In Dokploy UI:
|
|
- Create project: `ai-stack-deployer-portal`
|
|
- Create application from Docker image
|
|
- Set domain: `portal.ai.flexinit.nl`
|
|
- Configure environment variables
|
|
- Deploy
|
|
|
|
3. Verify:
|
|
```bash
|
|
curl https://portal.ai.flexinit.nl/health
|
|
```
|
|
|
|
## API Documentation
|
|
|
|
### Endpoints
|
|
|
|
#### Health Check
|
|
```http
|
|
GET /health
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"status": "healthy",
|
|
"timestamp": "2026-01-09T12:00:00.000Z",
|
|
"version": "0.1.0",
|
|
"service": "ai-stack-deployer",
|
|
"activeDeployments": 0
|
|
}
|
|
```
|
|
|
|
#### Check Name Availability
|
|
```http
|
|
GET /api/check/:name
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"available": true,
|
|
"valid": true,
|
|
"name": "john-dev"
|
|
}
|
|
```
|
|
|
|
#### Deploy Stack
|
|
```http
|
|
POST /api/deploy
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "john-dev"
|
|
}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"deploymentId": "dep_1234567890_abc123",
|
|
"url": "https://john-dev.ai.flexinit.nl",
|
|
"statusEndpoint": "/api/status/dep_1234567890_abc123"
|
|
}
|
|
```
|
|
|
|
#### Deployment Status (SSE)
|
|
```http
|
|
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 operations
|
|
- `HETZNER_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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
# Start MCP server
|
|
bun run mcp
|
|
```
|
|
|
|
Available MCP tools:
|
|
- `deploy_stack` - Deploy a new AI stack
|
|
- `check_deployment_status` - Query deployment progress
|
|
- `list_deployments` - List all deployments
|
|
- `check_name_availability` - Validate stack name
|
|
- `test_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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
1. Check Dokploy API connectivity:
|
|
```bash
|
|
curl -H "x-api-key: YOUR_TOKEN" http://10.100.0.20:3000/api/project.all
|
|
```
|
|
|
|
2. View deployment logs in browser console (F12)
|
|
|
|
3. Check server logs for errors:
|
|
```bash
|
|
docker-compose logs -f | grep ERROR
|
|
```
|
|
|
|
### Name Already Taken
|
|
|
|
If a deployment fails but the name is marked as taken:
|
|
1. Check Dokploy UI for the project `ai-stack-{name}`
|
|
2. Delete the partial deployment if present
|
|
3. 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**
|