StackWiz Guide - Service Creation Wizard¶
What is StackWiz?¶
StackWiz is a custom interactive tool that automates the creation of new Docker service stacks with proper Traefik integration, standardized structure, and security defaults.
Location: /srv/dockerdata/_templates/stackwiz
Quick Start¶
Interactive Mode (Recommended)¶
Non-Interactive Mode¶
# Generic service
sudo stackwiz -n myapp -d myapp.rbnk.uk -i nginx:alpine -p 80 --yes
# Pocketbase service
sudo stackwiz -n mybackend -d api.rbnk.uk --type pocketbase --yes
# With automatic DNS creation
sudo stackwiz -n myapp -d myapp.rbnk.uk -i nginx:alpine -p 80 --create-dns --yes
The Two Stack Types¶
1. Generic Stack¶
For any Docker container - databases, web apps, tools, custom services.
You provide: - Container image (with full registry path if not Docker Hub) - Internal port the container listens on - Domain name for access
Examples:
- Web apps: ghost:5-alpine (port 2368)
- Databases: redis:7-alpine (port 6379)
- Tools: grafana/grafana:10.2.0 (port 3000)
2. Pocketbase Stack¶
Pre-configured backend-as-a-service with SQLite database, auth, and admin UI.
Automatically configured:
- Image: ghcr.io/muchobien/pocketbase:latest
- Port: 8080
- Volumes for data persistence
- Encryption setup required
Interactive Wizard Walkthrough¶
Step 1: Choose Stack Type¶
Select stack type:
1) generic (any Docker container)
2) pocketbase (Backend-as-a-Service)
Enter choice [1]:
Decision Guide:
- Choose generic for: existing Docker images, databases, tools
- Choose pocketbase for: new projects needing backend, rapid prototyping
Step 2: App Name (Slug)¶
Requirements: - Lowercase letters, numbers, hyphens only - No spaces or special characters - Will become: directory name, container name, router name
Examples:
- ✅ redis-cache, api-v2, monitoring
- ❌ My App, app_name, App!
Step 3: Domain Name¶
Format: - Full domain including subdomain - No protocol (http://) - No trailing slash
Planning Tip:
- APIs: api.project.domain
- Frontends: app.project.domain or project.domain
- Admin tools: admin.project.domain
Step 4: Container Image (Generic Only)¶
Format: [registry/]namespace/image[:tag]
Finding Images: 1. Check project documentation for official image 2. Search Docker Hub 3. Look for badges in GitHub README
Registry Examples:
- Docker Hub: nginx:alpine (default)
- GitHub: ghcr.io/username/image:tag
- Google: gcr.io/project/image:tag
- Quay: quay.io/organization/image:tag
Best Practices:
- Always specify version tag (not :latest)
- Prefer official images
- Use Alpine variants for smaller size
Step 5: Container Port (Generic Only)¶
How to Find:
1. Check image documentation on Docker Hub
2. Look for "Exposed Ports" section
3. Search for EXPOSE in Dockerfile
Common Ports: - Node.js apps: 3000, 8080 - Python apps: 5000, 8000 - Nginx: 80 - Databases: PostgreSQL (5432), MySQL (3306), Redis (6379)
Important: This is the port INSIDE the container, not the external port you'll access (which is always 443 via HTTPS).
Step 6: Edit Configuration¶
When to Edit .env: - Add API keys or passwords - Configure application settings - Adjust resource limits
When to Edit Config: - Application needs config file - Complex YAML/JSON configuration
Step 7: DNS Record Creation¶
What This Does:
- Automatically creates an A record in Cloudflare
- Points to the server's public IP address
- Extracts subdomain from the full domain (e.g., myapp.rbnk.uk → myapp)
- Falls back gracefully if Cloudflare API token isn't configured
Say Yes if: - You want automatic DNS setup - Cloudflare manages your domain - API token is configured in the system
Say No if: - DNS is already configured - Using a different DNS provider - Want to configure DNS manually later
Step 8: Auto-Start¶
Say Yes if: Ready to test immediately Say No if: Need to add more files or configuration first
What StackWiz Creates¶
Directory Structure¶
/srv/dockerdata/myapp/
├── docker-compose.yml # Service definition
├── .env # Environment variables (mode 640)
├── data/ # Persistent data directory
└── config/ # Configuration files
└── app-config.yaml # Generic config template
Docker Compose File¶
For generic services:
services:
myapp:
image: ${APP_IMAGE}
container_name: ${APP_NAME}
restart: unless-stopped
env_file: ./.env
networks:
- default
volumes:
- ./data:/data
- ./config:/config
labels:
# Traefik configuration (automatic)
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`myapp.rbnk.uk`)"
# ... SSL and routing setup
Environment File¶
# Base configuration
APP_NAME=myapp
APP_IMAGE=nginx:alpine
APP_PORT=80
APP_DOMAIN=myapp.rbnk.uk
# Traefik settings (standardized)
TRAEFIK_NETWORK=traefik_proxy
TRAEFIK_CERTRESOLVER=cf
TRAEFIK_ENTRYPOINT=websecure
# Add your secrets below
# API_KEY=
# DATABASE_URL=
Key Decisions Explained¶
Why Token Substitution?¶
StackWiz uses tokens like __APP_NAME__ in templates:
Benefits: - Consistency across all services - Easy to maintain templates - Prevents typos and errors
Why Docker Labels for Traefik?¶
Instead of editing Traefik config files:
Benefits: - Service self-registers with Traefik - No Traefik restart needed - Configuration travels with service
Why Separate .env File?¶
Security: Different permissions than docker-compose.yml Portability: Same compose file, different environments Git Safety: Easy to .gitignore secrets
Why Standard Directory Structure?¶
Every service follows:
Benefits: - Predictable for maintenance - Easy backup strategy - Clear service boundaries
Common Image Examples¶
Web Applications¶
# Ghost Blog
stackwiz -n blog -d blog.site.com -i ghost:5-alpine -p 2368
# WordPress
stackwiz -n wp -d site.com -i wordpress:6-php8.2-apache -p 80
# Node.js App
stackwiz -n api -d api.site.com -i node:20-alpine -p 3000
Databases¶
# PostgreSQL
stackwiz -n postgres -d db.internal -i postgres:15-alpine -p 5432
# Redis Cache
stackwiz -n redis -d redis.internal -i redis:7-alpine -p 6379
# MongoDB
stackwiz -n mongo -d mongo.internal -i mongo:7 -p 27017
Tools¶
# Grafana
stackwiz -n grafana -d metrics.site.com -i grafana/grafana:10.2.0 -p 3000
# Portainer
stackwiz -n portainer -d docker.site.com -i portainer/portainer-ce:latest -p 9000
# Prometheus
stackwiz -n prometheus -d prom.site.com -i prom/prometheus:latest -p 9090
Advanced Usage¶
DNS Record Management¶
StackWiz can automatically create DNS records in Cloudflare:
Interactive Mode: You'll be prompted during setup
Non-Interactive Mode: Use the --create-dns flag
# Create stack with automatic DNS
sudo stackwiz -n myapp -d myapp.rbnk.uk -i nginx:alpine -p 80 --create-dns --yes
Requirements:
- Cloudflare API token configured on the system
- Domain must be managed by Cloudflare
- cloudflare-dns-create.sh script available in _scripts/
How It Works: 1. Extracts subdomain from full domain (supports multi-level subdomains) 2. Creates A record pointing to server's public IP 3. Falls back gracefully if API token missing or creation fails
Manual DNS Creation: If automatic creation fails or you prefer manual setup:
# Simple method (A records only)
/srv/dockerdata/_scripts/cloudflare-dns-create.sh subdomain
# Or use the advanced tool for full control
cloudflare-dns create A subdomain AUTO
Advanced DNS Management: For complex DNS configurations (CNAME, MX, TXT records), use the advanced tool:
# Set up the advanced DNS tool
sudo ln -s /srv/dockerdata/_scripts/cloudflare-dns.sh /usr/local/bin/cloudflare-dns
# Examples
cloudflare-dns create CNAME www myapp.rbnk.uk
cloudflare-dns list
cloudflare-dns --help
See DNS Management Documentation for comprehensive DNS operations.
Custom Networks¶
If service needs multiple networks:
# Edit docker-compose.yml after generation
networks:
- default # traefik_proxy
- internal_net # Your internal network
Volume Mapping¶
Common patterns to add:
volumes:
- ./data:/var/lib/postgresql/data # PostgreSQL
- ./data:/data/db # MongoDB
- ./data:/var/lib/mysql # MySQL
- ./data:/var/lib/redis # Redis persistence
Health Checks¶
Add after generation:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:${APP_PORT}/health"]
interval: 30s
timeout: 10s
retries: 3
Resource Limits¶
Add to prevent runaway containers:
Troubleshooting¶
"Bad Gateway" Error¶
Cause: Wrong container port specified
Fix:
1. Check actual port: docker logs CONTAINER_NAME
2. Update in docker-compose.yml
3. Restart: docker compose up -d
"Name Not Resolved"¶
Cause: DNS not configured for domain
Fix: 1. If you skipped DNS creation during setup, run:
2. Or manually add A record pointing to server IP 3. Wait for DNS propagation (1-5 minutes) 4. Test:dig yourdomain.com
DNS Creation Failed¶
Possible Causes: - Cloudflare API token not configured - Domain not managed by Cloudflare - Subdomain already exists
Fix:
1. Check API token: echo $CF_DNS_API_TOKEN
2. Verify domain is in Cloudflare
3. Create record manually in Cloudflare dashboard
Container Keeps Restarting¶
Check:
# View logs
docker logs CONTAINER_NAME
# Common issues:
# - Missing environment variables
# - Wrong file permissions
# - Port already in use
Image Pull Errors¶
For non-Docker Hub images, use full path:
- ❌ open-webui/open-webui:main
- ✅ ghcr.io/open-webui/open-webui:main
Git Integration¶
Working with Version Control¶
When creating new services with StackWiz, follow these Git practices:
# 1. Create feature branch for new service
git checkout -b feature/add-myservice
# 2. Run StackWiz
stackwiz myservice
# 3. Configure and test the service
cd myservice
# Edit .env and docker-compose.yml as needed
docker compose up -d
# 4. Create .env.example (IMPORTANT!)
cp .env .env.example
# Remove sensitive values from .env.example
vim .env.example
# 5. Commit changes
git add myservice/
git commit -m "feat(services): add myservice stack
- Configure myservice with Traefik integration
- Set up persistent storage volumes
- Add environment template for easy deployment"
# 6. Push to Gitea (primary repository)
git push -u origin feature/add-myservice
# 7. After review/approval, merge and sync
git checkout main
git merge feature/add-myservice
git push origin main
git push github main # If using GitHub mirror
Security Considerations¶
StackWiz creates .env files with sensitive data. Always:
- Check .gitignore: Ensure
*.envis listed - Create .env.example: Template without secrets
- Review before commit:
git diff --staged - Use pre-commit hooks: Install security checks
Best Practices¶
1. Plan Your Domains¶
- Consistent naming scheme
- Consider subdomains for organization
- Reserve some for internal services
2. Version Control¶
cd /srv/dockerdata
# If not already a git repository
git init
# Configure dual remotes (Gitea primary, GitHub secondary)
/srv/dockerdata/_scripts/setup-git-remotes.sh
# Add your new service
git add SERVICE_NAME/
git commit -m "Add SERVICE_NAME stack"
# Push to Gitea (primary)
git push origin main
# Optionally push to GitHub
git push github main
3. Test Locally First¶
# Test image works
docker run --rm -p 8080:INTERNAL_PORT IMAGE_NAME
# Access at http://localhost:8080
4. Document Custom Configuration¶
Add README.md to service directory:
# Service Name
## Purpose
What this service does
## Configuration
- Required environment variables
- Important settings
## Maintenance
- How to backup
- Update procedure
The Magic of StackWiz¶
StackWiz transforms a complex process: - Creating directories with correct permissions - Writing valid docker-compose.yml - Configuring Traefik labels correctly - Setting up SSL automatically - Creating standard structure
Into a simple wizard that takes 30 seconds.
Remember: StackWiz creates the foundation. You can always customize the generated files for specific needs!