feat(SCOPONE-0010): vendor agent assets and clean docs

This commit is contained in:
Giancarmine Salucci
2026-04-10 22:35:01 +02:00
parent a4e2891c87
commit 5370876db3
32 changed files with 4046 additions and 81 deletions

601
.github/skills/deploy-app/README.md vendored Normal file
View File

@@ -0,0 +1,601 @@
# Deploy Application Skill
Automated deployment of Dockerized applications to remote servers.
## Features
**Automated Docker builds and registry pushes** to Gitea
**SSH-based remote deployment** with compose orchestration
**Automatic reverse proxy** configuration with Nginx Proxy Manager
**Subdomain routing** - Apps served as `{app-name}.{root-domain}`
**SSL certificate** generation via Let's Encrypt
**Smart .env handling** - Auto-generates secrets, infers service URLs
**Network topology** management (proxy, ollama)
**No host port publishing** - Webapps are reached through Docker network + Nginx Proxy Manager
**Organized data storage** - All volumes under `./data/`
**Health monitoring** and log inspection
**Rollback guidance** on failures
**Update-aware deployments** - Detects existing stack/proxy and performs safe in-place updates
## Quick Start
### 1. Run Setup Wizard
```bash
cd .github/skills/deploy-app
chmod +x setup-wizard.sh
./setup-wizard.sh
```
Follow the prompts to generate your deployment configuration.
### 2. Deploy Your App
```
deploy production
```
That's it! The agent will handle both first deploys and updates.
If the remote stack directory or proxy host already exists, deployment is treated as an **update** (with idempotent proxy handling and additive env/volume changes).
## Files
- **SKILL.md** - Complete skill documentation (for the agent)
- **setup-wizard.sh** - Interactive configuration generator
- **README.md** - This file (user documentation)
## What Gets Deployed
```
Remote Server: /srv/docker/stacks/my-app/
├── compose.yaml # Generated Docker Compose file
├── .env # Environment variables (if detected)
└── data/ # Persistent application data
├── <app-data> # Main application data
├── uploads/ # If app needs uploads (auto-detected)
├── cache/ # If app needs cache (auto-detected)
└── logs/ # If app needs logs (auto-detected)
```
All volumes are organized under the `data/` directory for clean separation.
## Supported Application Types
- **webapp** - Web applications with reverse proxy and SSL
- **service** - Backend services without public access
- **worker** - Background workers and queue processors
## Requirements
**Local:**
- Docker installed
- Access to workspace with Dockerfile
- Environment variable `DEPLOY_CONFIG_{TARGET}` configured
**Remote Server:**
- Docker and Docker Compose installed
- SSH access configured
- Docker networks created (`proxy`, optionally `ollama`)
**Services:**
- Gitea instance with container registry enabled
- Nginx Proxy Manager (for webapps)
## Configuration
See configuration examples below for different deployment scenarios.
### Production Server
```bash
export DEPLOY_CONFIG_PRODUCTION='{
"gitea_registry_url": "gitea.mycompany.com",
"gitea_username": "deploy-bot",
"gitea_token": "a1b2c3d4e5f6g7h8i9j0",
"gitea_namespace": "production-apps",
"ssh_host": "prod-server",
"stacks_dir": "/srv/docker/stacks",
"domain": "sal.giize.com",
"npm_url": "https://proxy.mycompany.com",
"npm_username": "admin@mycompany.com",
"npm_password": "npm-admin-password"
}'
# All app-specific settings (name, port, env vars, volumes, type)
# are auto-detected from your codebase!
# App will be served at: {app-name}.sal.giize.com
```
### Staging Server
```bash
export DEPLOY_CONFIG_STAGING='{
"gitea_registry_url": "gitea.mycompany.com",
"gitea_username": "deploy-bot",
"gitea_token": "a1b2c3d4e5f6g7h8i9j0",
"gitea_namespace": "staging-apps",
"ssh_host": "staging-server",
"stacks_dir": "/home/deploy/stacks",
"domain": "staging.sal.giize.com",
"npm_url": "https://proxy-staging.mycompany.com",
"npm_username": "admin@mycompany.com",
"npm_password": "npm-admin-password"
}'
```
### AI Service with LLM
```bash
export DEPLOY_CONFIG_AI_SERVICE='{
"gitea_registry_url": "gitea.mycompany.com",
"gitea_username": "deploy-bot",
"gitea_token": "a1b2c3d4e5f6g7h8i9j0",
"gitea_namespace": "ai-services",
"ssh_host": "ai-server",
"stacks_dir": "/srv/docker/stacks",
"domain": "ai.sal.giize.com",
"npm_url": "https://proxy.mycompany.com",
"npm_username": "admin@mycompany.com",
"npm_password": "npm-admin-password",
"proxy_network": "proxy",
"ollama_network": "ollama",
"ollama_container_name": "ollama"
}'
# Network names are customizable
# App will auto-connect to Ollama at: http://ollama:11434
# (or your custom ollama_container_name:11434)
```
### Background Worker (No Web Interface)
For services without a web interface, omit the NPM fields:
```bash
export DEPLOY_CONFIG_WORKER='{
"gitea_registry_url": "gitea.mycompany.com",
"gitea_username": "deploy-bot",
"gitea_token": "a1b2c3d4e5f6g7h8i9j0",
"gitea_namespace": "workers",
"ssh_host": "worker-server",
"stacks_dir": "/srv/docker/stacks"
}'
```
### Configuration Fields
**Required for All Deployments:**
- `gitea_registry_url` - Your Gitea instance domain (without https://)
- `gitea_username` - Gitea username
- `gitea_token` - Access token with package permissions
- `gitea_namespace` - Organization or username
- `ssh_host` - SSH alias from ~/.ssh/config
- `stacks_dir` - Directory on remote server for stacks
**Required for Webapps:**
- `domain` - Root domain (e.g., `sal.giize.com`). App will be served at `{app-name}.{domain}`
- `npm_url` - Nginx Proxy Manager URL
- `npm_username` - NPM admin email
- `npm_password` - NPM admin password
**Optional Network Configuration:**
- `proxy_network` - Docker network name for reverse proxy (default: `proxy`)
- `ollama_network` - Docker network name for Ollama LLM (default: `ollama`)
- `ollama_container_name` - Ollama container name for URL generation (default: `ollama`)
- Apps requiring LLM will auto-set `OLLAMA_BASE_URL=http://{ollama_container_name}:11434`
**Auto-Detected from Codebase:**
- **App name** - From package.json, Cargo.toml, pyproject.toml, go.mod, or directory name
- **Port** - From Dockerfile EXPOSE, .env PORT, code patterns, or defaults to 3000
- Used as internal container port for proxy upstream (not published on host by default)
- **App type** - webapp/service/worker based on dependencies and keywords
- **Environment variables** - Smart .env processing:
- 🔐 Auto-generates secrets (JWT_SECRET, APP_KEY, etc.) using secure random values
- 🔌 Infers service URLs (DATABASE_URL, REDIS_URL) from dependencies
- 📋 Copies simple values (NODE_ENV, LOG_LEVEL) as-is
- ❓ Asks for external API keys and credentials
- **Volume mounts** - From README, Dockerfile VOLUME, common directories (bound under ./data/)
- **LLM requirements** - From dependencies (openai, ollama, llama)
All detected settings are confirmed with you before deployment.
**Volume Binding:** All volumes are automatically bound under `./data/` on the host.
Example: If app needs uploads, it creates `./data/uploads:/app/uploads`
**Domain Handling:** The `domain` field is the root domain. Your app is served as a subdomain.
Example: `domain: "sal.giize.com"` + app name `my-api` → URL: `my-api.sal.giize.com`
**DNS Requirements:** Ensure you have a wildcard DNS record or individual A/CNAME records:
- Wildcard: `*.sal.giize.com``your-server-ip`
- Individual: `my-api.sal.giize.com``your-server-ip`
## Deployment Flow
1. **Parse target** - Extract deployment target name
2. **Auto-detect app** - Scan codebase for app name, port, type, env vars, volumes, LLM usage
3. **Process .env** - Generate secrets, infer service URLs, identify user inputs
4. **Load config** - Get server/credential configuration
5. **Detect mode** - Classify deployment as `new` or `update` using existing remote stack/proxy state
6. **Confirm detection** - Show detected config and mode, ask for approval
7. **Confirm environment** - Review .env processing and provide any needed values
8. **Validate** - Check Dockerfile exists
9. **Build** - Test build locally
10. **Push** - Tag and push to Gitea registry
11. **Transfer** - SSH to remote server
12. **Setup** - Create/update directories, deploy merged `.env` and compose files
13. **Deploy** - `docker compose down`, `docker compose pull`, `docker compose up -d`
14. **Configure** - Create or update reverse proxy (webapps)
- Upstream target uses Docker service + internal port (for example `my-app:3000`)
15. **Verify** - Inspect logs and test application availability
## Key Features Explained
### Subdomain Routing
Apps are automatically served as subdomains of your root domain:
- Config: `"domain": "sal.giize.com"`
- App name: `my-api` (auto-detected)
- **Result:** App accessible at `my-api.sal.giize.com`
**DNS Setup:** Configure wildcard DNS: `*.sal.giize.com` → your server IP
### Volume Organization
All persistent data is organized under `./data/`:
```
data/
├── <app-data>/ # Main app data (always created)
├── uploads/ # Auto-detected from codebase
├── cache/ # Auto-detected from codebase
└── logs/ # Auto-detected from codebase
```
Docker compose mounts: `./data/uploads:/app/uploads`
### Auto-Detection
The skill scans your codebase to detect:
- App name from package.json, Cargo.toml, pyproject.toml, go.mod, or directory
- Container port from Dockerfile EXPOSE, .env, or code patterns
- App type (webapp/service/worker) from dependencies
- Environment variables from .env files
- Volume requirements from README, Dockerfile, common patterns
- LLM dependencies (openai, ollama)
All detected settings shown to you for confirmation before deployment.
### Smart .env Handling
When a `.env`, `.env.example`, or `.env.template` file is detected, the skill intelligently processes it:
**🔐 Auto-Generated Secrets**
Variables like `JWT_SECRET`, `APP_KEY`, `SESSION_SECRET` are automatically generated using secure random values:
```bash
JWT_SECRET=a1b2c3d4e5f6... # 32-byte hex string
```
**🔌 Inferred Service URLs**
Database and service connections are constructed from container names based on detected dependencies:
```bash
DATABASE_URL=postgresql://my-app-db:5432/my-app
REDIS_URL=redis://my-app-redis:6379
MONGODB_URI=mongodb://my-app-mongo:27017/my-app
```
**📋 Copied Values**
Simple configuration values are preserved:
```bash
NODE_ENV=production
LOG_LEVEL=info
TZ=UTC
```
**❓ User Input**
External API keys and credentials are identified and you're prompted for values:
```bash
STRIPE_SECRET_KEY=sk_live_... # You'll be asked to provide this
SENDGRID_API_KEY=SG... # You'll be asked to provide this
```
**Confirmation**
Before deployment, you'll see:
- What was generated (with secure random values)
- What was inferred (service URLs)
- What was copied (simple configs)
- What needs your input (API keys)
You can proceed as-is or provide specific values. The complete `.env` file is deployed to the server with secure permissions (chmod 600).
### Update-Safe Drift Handling
When deployment mode is `update`, the skill applies additive and non-destructive changes:
- **Environment merge:** existing remote `.env` keys are preserved; newly required keys are appended.
- **Required secrets:** unresolved required placeholders still block deployment until provided.
- **Volume drift:** new host directories are created as needed; existing volume paths are kept intact.
- **Compose stability:** service naming remains stable for idempotent updates.
This minimizes downtime and avoids accidental configuration loss during redeployments.
## Quick Setup Guide
### 1. Create Gitea Token
```bash
# Login to Gitea
# Navigate to Settings → Applications → Generate New Token
# Select scopes: write:package, read:package
# Copy the generated token
```
### 2. Configure SSH
```bash
# Edit ~/.ssh/config
cat >> ~/.ssh/config << 'EOF'
Host prod-server
HostName 192.168.1.100
User deploy
IdentityFile ~/.ssh/deploy_key
StrictHostKeyChecking accept-new
EOF
# Test connection
ssh prod-server "echo 'Connection successful'"
```
### 3. Prepare Remote Server
```bash
# SSH to server
ssh prod-server
# Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Create networks (run once per server)
# Use your configured network names (defaults shown below)
docker network create proxy # or your proxy_network value
docker network create ollama # or your ollama_network value (for LLM apps)
# Create stacks directory
sudo mkdir -p /srv/docker/stacks
sudo chown $USER:$USER /srv/docker/stacks
```
### 4. Set Environment Variable
**Linux/macOS** (add to ~/.bashrc or ~/.zshrc):
```bash
export DEPLOY_CONFIG_PRODUCTION='{ ... your JSON config ... }'
```
**Windows PowerShell**:
```powershell
$config = @'
{ ... your JSON config ... }
'@
[System.Environment]::SetEnvironmentVariable('DEPLOY_CONFIG_PRODUCTION', $config, 'User')
```
### 5. Deploy
Just tell the agent:
```
deploy production
```
## Security
- Credentials stored in environment variables only
- SSH key-based authentication
- Secrets never logged to output
- HTTPS with Let's Encrypt certificates
- Docker registry authentication
## Troubleshooting
### Quick Diagnostics
```bash
# Check environment variable
echo $DEPLOY_CONFIG_PRODUCTION
# Test SSH
ssh prod-server "docker ps"
# Test Gitea registry
docker login gitea.example.com -u username
# Check remote deployment
ssh prod-server "cd /srv/docker/stacks/my-app && docker compose logs"
```
### Common Issues
**"DEPLOY_CONFIG_{TARGET} not found"**
- Make sure you've exported the environment variable
- Restart your terminal/VS Code after setting it
- Check spelling and capitalization
**"Cannot connect to {ssh_host}"**
- Verify SSH config: `cat ~/.ssh/config`
- Test connection: `ssh {ssh_host} "echo test"`
- Check SSH key permissions: `chmod 600 ~/.ssh/deploy_key`
**"Authentication failed" (Gitea)**
- Regenerate token with correct permissions
- Ensure token hasn't expired
- Verify username is correct
**"Docker login failed"**
- Check gitea_registry_url doesn't have protocol (no https://)
- Verify token has package write permission
- Try manual login: `echo "TOKEN" | docker login gitea.example.com -u user --password-stdin`
**Container fails to start**
- Check logs: `ssh server "cd /srv/docker/stacks/app && docker compose logs"`
- Verify environment variables are correct
- Check port conflicts on server
- Ensure image pulled successfully
**Environment variables not working**
- Check .env file exists: `ssh server "cat /srv/docker/stacks/app/.env"`
- Verify .env file permissions: `ssh server "ls -la /srv/docker/stacks/app/.env"` (should be 600)
- Ensure compose.yaml has `env_file: [.env]` directive
- Test variable loading: `ssh server "cd /srv/docker/stacks/app && docker compose config"` (shows resolved env vars)
- Restart containers after .env changes: `ssh server "cd /srv/docker/stacks/app && docker compose restart"`
**Missing or incorrect service URLs**
- Verify service containers are running in same network
- Check container names match .env URLs (e.g., `my-app-db` for DATABASE_URL)
- Test connectivity: `ssh server "docker exec my-app ping my-app-db"`
- Review auto-generated URLs in deployment confirmation step
**NPM SSL certificate fails**
- Verify domain DNS points to your server
- Check ports 80 and 443 are open
- Ensure domain is publicly accessible
- Check NPM can reach Let's Encrypt servers
## API Documentation
### Gitea Container Registry
Gitea uses an OCI-compliant container registry. No special API calls needed - just standard Docker commands:
```bash
docker login {gitea_url}
docker tag image:tag {gitea_url}/{namespace}/{name}:tag
docker push {gitea_url}/{namespace}/{name}:tag
```
Images are automatically visible in Gitea under Packages.
### Nginx Proxy Manager API
Main endpoints used:
- `POST /api/tokens` - Authentication
- `POST /api/nginx/proxy-hosts` - Create reverse proxy
- `POST /api/nginx/certificates` - Request SSL cert
- `PUT /api/nginx/proxy-hosts/{id}` - Update with SSL
## Examples
### Deploy to Production
```
deploy production
```
If `production` already exists remotely, this runs as an update rollout.
### Deploy to Staging
```
deploy staging
```
If the stack already exists, the skill updates it in place.
### Deploy AI Service with LLM
```
deploy ai-service
```
For existing deployments, proxy and stack are updated idempotently.
## Advanced Usage
### Modifying Environment Variables After Deployment
If you need to update environment variables after deployment:
**Option 1: Edit .env on server**
```bash
# SSH to server and edit
ssh prod-server
cd /srv/docker/stacks/my-app
nano .env
# Restart containers to apply changes
docker compose restart
```
**Option 2: Redeploy with updated .env**
Update your local `.env` file and redeploy - the skill will process it again in update mode and merge new required keys without deleting existing ones.
### Adding Service Containers
If your app needs a database or other services, create them in the same stack:
```bash
ssh prod-server
cd /srv/docker/stacks/my-app
nano compose.yaml
```
Add service definitions:
```yaml
services:
my-app:
# ... existing config
depends_on:
- db
- redis
db:
image: postgres:16
container_name: my-app-db
environment:
POSTGRES_DB: my-app
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- ./data/postgres:/var/lib/postgresql/data
redis:
image: redis:7
container_name: my-app-redis
volumes:
- ./data/redis:/data
```
The DATABASE_URL and REDIS_URL will already be correctly set by the auto-detection!
### Additional Volumes
```json
{
"volumes": [
"./uploads:/app/uploads",
"./cache:/app/cache:ro"
]
}
```
### Multiple Targets
Create multiple configs:
```bash
export DEPLOY_CONFIG_PRODUCTION='{ ... }'
export DEPLOY_CONFIG_STAGING='{ ... }'
export DEPLOY_CONFIG_DEVELOPMENT='{ ... }'
```
Deploy to any target:
```
deploy development
deploy staging
deploy production
```
## License
Part of the Copilot Agents skill library.

177
.github/skills/deploy-app/SKILL.md vendored Normal file
View File

@@ -0,0 +1,177 @@
---
name: deploy-app
description: Automated deployment of Dockerized applications to remote servers with Gitea registry, Docker Compose orchestration, and Nginx Proxy Manager integration.
---
# Deploy Application
Lean-mode deployment contract for token-efficient execution. Use this file for runtime behavior. For deep examples and full walkthroughs, reference [README.md](./README.md).
## Prerequisites
- `DEPLOY_CONFIG_{TARGET}` env var exists and is valid JSON
- SSH host alias works from `~/.ssh/config`
- `Dockerfile` exists in workspace root
- Docker available locally and on target server
## Deployment Steps
### 1. Parse target
Extract `{TARGET}` from user request (for example: `deploy production``PRODUCTION`).
### 2. Detect app metadata (minimal set)
Detect and store:
- `{app_name}`: from `package.json` / `Cargo.toml` / `pyproject.toml` / `go.mod` / directory fallback
- `{port}`: from `EXPOSE`, `.env PORT`, or framework patterns; fallback `3000` (container internal port)
- `{app_type}`: `webapp`, `service`, or `worker`
- `{requires_llm}`: true if `openai|ollama|llama` detected
- `{detected_volumes}`: bind all host paths under `./data/` (including secrets paths)
If `.env*` exists (excluding `.env.local`), process variables into:
- generated secrets (`*SECRET*`, `*KEY`, `*TOKEN`)
- inferred service URLs (`DATABASE_URL`, `REDIS_URL`, etc.)
- copied simple values (`NODE_ENV`, `PORT`, `LOG_LEVEL`, ...)
- user-required values (placeholders/external API keys)
### 3. Load and validate deploy config
Read `DEPLOY_CONFIG_{TARGET}` and validate required fields:
- `gitea_registry_url`, `gitea_username`, `gitea_token`, `gitea_namespace`
- `ssh_host`, `stacks_dir`
If missing/invalid: STOP with explicit error.
### 4. Confirm detected configuration
Use `ask_questions` with detected summary (app, port, type, env, volumes, URL if webapp, deploy mode).
If user declines, STOP and request adjustments.
If user-input env values are required, collect them before continuing.
### 5. Validate and build locally
Verify Dockerfile exists, then run:
- `docker build -t {app_name}:test-build .`
If build fails: STOP and report error output.
### 6. Push image to registry
1. Login with `--password-stdin`
2. Tag as `latest` and `{timestamp}` (`YYYYMMDD-HHMMSS`)
3. Push both tags
If auth/network/permission fails: STOP with targeted troubleshooting.
### 7. Detect deploy mode (new vs update)
On remote host and in NPM API (when configured), detect:
- stack path exists: `{stacks_dir}/{app_name}`
- compose file exists: `{stacks_dir}/{app_name}/compose.yaml`
- proxy host exists for `{app_name}.{domain}` (webapp only)
Classification:
- `new`: none of the above exist
- `update`: stack path or proxy host already exists
If only one side exists (for example proxy exists but stack does not, or inverse), continue in cautious update mode and include this mismatch in confirmation.
### 8. Prepare remote stack
1. Verify SSH connectivity
2. Create `{stacks_dir}/{app_name}/data` and required subdirectories
3. Process `.env` with update-safe merge strategy:
- if update and remote `.env` exists, preserve existing keys/values
- append newly required keys not present remotely
- never delete existing keys automatically
- block on unresolved required user-input secrets/placeholders
4. Apply secure permissions to remote `.env` (`chmod 600`)
5. Handle volume drift safely:
- create newly required host directories
- enforce all volume and secrets host paths as children of `./data/`
- keep existing volume paths intact
- never remove existing volume mounts automatically
### 9. Generate and upload compose.yaml
Compose requirements:
- image: `{gitea_registry_url}/{gitea_namespace}/{app_name}:latest`
- restart: `unless-stopped`
- all volumes and secrets host paths under `./data`
- do NOT publish ports on host (no `ports:` mapping by default)
- use external proxy network for `webapp`
- add ollama network and `OLLAMA_BASE_URL` when `{requires_llm}=true`
Update behavior for compose generation:
- keep service naming stable for idempotent updates
- preserve existing mounts/networks unless user explicitly confirms removal
- if update and env + volume definitions are unchanged, do NOT rewrite `compose.yaml`
- if update requires compose rewrite, fetch remote `compose.yaml` and use it as template baseline before applying required deltas
Upload compose file to `{stacks_dir}/{app_name}/compose.yaml`.
### 10. Deploy on server
On remote host:
1. `docker login` to registry
2. `docker compose down`
3. `docker compose pull`
4. `docker compose up -d`
4. Inspect logs (`--tail=50`) after short wait
If container exits or logs show startup failure: STOP and report logs.
### 11. Configure reverse proxy (webapp only)
If `{app_type}=webapp` and NPM config exists:
1. Authenticate to NPM API
2. Check if proxy host for `{app_name}.{domain}` already exists
3. Set upstream target to Docker service name + internal container port (`{app_name}:{port}`) on shared proxy network
4. If existing: update upstream target and SSL settings (idempotent update)
5. If not existing: create proxy host, request certificate, then enable SSL
If SSL creation fails: WARN and continue HTTP-only.
### 12. Verify deployment
- Webapp: `curl -I https://{app_name}.{domain}` and expect `2xx/3xx`
- Non-webapp: verify running container and health/log readiness
Return structured success summary (image, host, location, URL/container).
## Error Recovery
On failure:
1. Show concrete error
2. Provide immediate remediation steps
3. STOP (no implicit continuation)
4. Offer rollback option using ONLY non-destructive actions:
- run `docker compose down` in the app stack directory
- rollback changes in Nginx Proxy Manager (remove/disable created proxy host entries for this deploy)
## Forbidden Operations
Safety policy for this skill is strict:
- NEVER execute deletion commands on local or remote systems.
- NEVER run any `rm`-family or delete operations, including recursive deletes.
- NEVER use destructive cleanup commands that remove files, directories, volumes, or containers.
Allowed remediation is limited to:
- `docker compose down`
- rollback changes in Nginx Proxy Manager
If a remediation path would require deletion, STOP and report manual follow-up steps without executing destructive commands.
## Security
- Never print secrets in logs
- Use `--password-stdin` for all docker logins
- Quote shell variables
- Validate all required inputs before executing remote operations
## Notes
- Keep runtime behavior minimal and deterministic.
- For advanced examples, edge-case recipes, and setup wizard usage, see [README.md](./README.md).

View File

@@ -0,0 +1,139 @@
#!/bin/bash
# Quick setup script for deployment configuration
set -e
echo "==================================="
echo "Deployment Skill Setup Wizard"
echo "==================================="
echo ""
# Function to read input with default
read_input() {
local prompt="$1"
local default="$2"
local var_name="$3"
if [ -n "$default" ]; then
read -p "$prompt [$default]: " input
eval "$var_name=\"${input:-$default}\""
else
read -p "$prompt: " input
eval "$var_name=\"$input\""
fi
}
# Target name
read_input "Enter deployment target name (e.g., PRODUCTION, STAGING)" "" TARGET
TARGET=$(echo "$TARGET" | tr '[:lower:]' '[:upper:]')
echo ""
echo "--- Gitea Configuration ---"
read_input "Gitea registry URL (without https://)" "gitea.example.com" GITEA_URL
read_input "Gitea username" "" GITEA_USER
echo "Gitea token (will be hidden): "
read -s GITEA_TOKEN
echo ""
read_input "Gitea namespace (org or username)" "$GITEA_USER" GITEA_NAMESPACE
echo ""
echo "--- Remote Server Configuration ---"
read_input "SSH host alias (from ~/.ssh/config)" "" SSH_HOST
read_input "Stacks directory on remote server" "/srv/docker/stacks" STACKS_DIR
echo ""
echo "--- Webapp Configuration (optional, press Enter to skip) ---"
read_input "Root domain (e.g., sal.giize.com - app served as subdomain)" "" DOMAIN
# Conditional NPM fields
if [ -n "$DOMAIN" ]; then
read_input "Nginx Proxy Manager URL" "https://npm.example.com" NPM_URL
read_input "NPM admin email" "admin@example.com" NPM_USER
echo "NPM password (will be hidden): "
read -s NPM_PASS
echo ""
fi
echo ""
echo "--- Network Configuration (optional, press Enter for defaults) ---"
read_input "Proxy network name" "proxy" PROXY_NETWORK
read_input "Ollama network name (for AI/LLM apps)" "ollama" OLLAMA_NETWORK
read_input "Ollama container name (for deriving connection URL)" "ollama" OLLAMA_CONTAINER
# Generate JSON config
if [ -n "$DOMAIN" ]; then
JSON_CONFIG=$(cat <<EOF
{
"gitea_registry_url": "$GITEA_URL",
"gitea_username": "$GITEA_USER",
"gitea_token": "$GITEA_TOKEN",
"gitea_namespace": "$GITEA_NAMESPACE",
"ssh_host": "$SSH_HOST",
"stacks_dir": "$STACKS_DIR",
"domain": "$DOMAIN",
"npm_url": "$NPM_URL",
"npm_username": "$NPM_USER",
"npm_password": "$NPM_PASS",
"proxy_network": "$PROXY_NETWORK",
"ollama_network": "$OLLAMA_NETWORK",
"ollama_container_name": "$OLLAMA_CONTAINER"
}
EOF
)
else
JSON_CONFIG=$(cat <<EOF
{
"gitea_registry_url": "$GITEA_URL",
"gitea_username": "$GITEA_USER",
"gitea_token": "$GITEA_TOKEN",
"gitea_namespace": "$GITEA_NAMESPACE",
"ssh_host": "$SSH_HOST",
"stacks_dir": "$STACKS_DIR",
"proxy_network": "$PROXY_NETWORK",
"ollama_network": "$OLLAMA_NETWORK",
"ollama_container_name": "$OLLAMA_CONTAINER"
}
EOF
)
fi
echo ""
echo "==================================="
echo "Configuration generated!"
echo "==================================="
echo ""
echo "Add this to your shell configuration file (~/.bashrc, ~/.zshrc, etc.):"
echo ""
echo "export DEPLOY_CONFIG_$TARGET='$JSON_CONFIG'"
echo ""
echo "Then restart your terminal or run:"
echo "source ~/.bashrc # or ~/.zshrc"
echo ""
# Optionally write to file
read -p "Save to file? (y/n): " SAVE_FILE
if [ "$SAVE_FILE" = "y" ] || [ "$SAVE_FILE" = "Y" ]; then
CONFIG_FILE="deploy_config_${TARGET}.env"
echo "export DEPLOY_CONFIG_$TARGET='$JSON_CONFIG'" > "$CONFIG_FILE"
echo ""
echo "✓ Saved to $CONFIG_FILE"
echo "Load it with: source $CONFIG_FILE"
fi
echo ""
echo "==================================="
echo "Next Steps:"
echo "==================================="
echo ""
echo "1. Set the environment variable (see above)"
echo "2. Verify SSH access: ssh $SSH_HOST \"echo 'Test OK'\""
echo "3. Create Docker networks on remote server (run once per server):"
echo " ssh $SSH_HOST \"docker network create $PROXY_NETWORK\""
if [ -n "$OLLAMA_NETWORK" ]; then
echo " ssh $SSH_HOST \"docker network create $OLLAMA_NETWORK\" # For AI/LLM apps"
fi
echo "4. Navigate to your application directory"
echo "5. Tell the agent: 'deploy $TARGET'"
echo ""
echo "The agent will auto-detect your app's configuration and ask for confirmation!"
echo ""