Skip to content

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

sudo stackwiz

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)

Enter app name (slug format): my-awesome-app

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

Enter FQDN domain: myapp.rbnk.uk

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)

Enter container image: grafana/grafana:10.2.0

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)

Enter internal container port [8080]: 3000

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

Edit .env file? (Y/n): y
Edit config/app-config.yaml? (Y/n): n

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

Create DNS record in Cloudflare for myapp.rbnk.uk? (Y/n): y

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.ukmyapp) - 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

Start stack with docker compose up -d? (Y/n): y

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:

# Template
container_name: __APP_NAME__

# Becomes
container_name: myapp

Benefits: - Consistency across all services - Easy to maintain templates - Prevents typos and errors

Why Docker Labels for Traefik?

Instead of editing Traefik config files:

labels:
  - "traefik.http.routers.myapp.rule=Host(`myapp.rbnk.uk`)"

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:

SERVICE_NAME/
├── docker-compose.yml
├── .env
└── data/

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:

deploy:
  resources:
    limits:
      cpus: '2.0'
      memory: 2G
    reservations:
      cpus: '0.5'
      memory: 512M

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:

/srv/dockerdata/_scripts/cloudflare-dns-create.sh subdomain
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:

  1. Check .gitignore: Ensure *.env is listed
  2. Create .env.example: Template without secrets
  3. Review before commit: git diff --staged
  4. 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!