try.directtry.direct

From GitHub Repo to Production — A 5-Minute Stacker Tutorial

What You'll Build

In this tutorial, you'll deploy three real open-source projects using Stacker — no Docker expertise needed. By the end, you'll have:

  • A self-hosted analytics dashboard (Umami)
  • A privacy-focused web archiver (ArchiveBox)
  • An AWS-compatible local cloud emulator (Floci)

Each deployment takes two commands. Total time: under 5 minutes.

Quick Answer

The Stacker deployment pattern for any GitHub repo:
stacker init --from-github owner/repo --with-ai --force
stacker deploy --target local
That's it. Stacker handles project detection, Docker configuration, service setup, healthchecks, env vars, and secrets generation.

Prerequisites

  • Docker installed (docker --version)
  • Git installed (git --version)
  • Optional: Ollama running locally for AI-assisted config (ollama serve)

Step 1: Install Stacker

curl -fsSL https://raw.githubusercontent.com/trydirect/stacker/main/install.sh | bash
stacker --version
# Should print: stacker 0.3.0

Step 2: Deploy Umami Analytics

Umami is a privacy-first, open-source alternative to Google Analytics. It uses PostgreSQL for data storage and runs on Node.js.

2.1 Generate the configuration

mkdir ~/umami && cd ~/umami
stacker init --from-github umami-software/umami --with-ai --force

Stacker clones the repo, reads the docker-compose.yml, detects a Node.js app with a PostgreSQL dependency, and generates:

# What you'll see in your directory:
stacker.yml              # The deployment config
.stacker/Dockerfile      # Optimized Node.js Dockerfile
.stacker/docker-compose.yml  # Production compose file
.env.example             # Template with detected env vars
scripts/generate-secrets.sh  # Auto-generate DB passwords

2.2 Generate secrets and deploy

cp .env.example .env
./scripts/generate-secrets.sh   # Fills in DB_PASSWORD, etc.
stacker config validate          # ✓ Configuration is valid
stacker deploy --target local    # Builds and starts containers

2.3 Verify

stacker status
# Should show: umami (running), postgres (running)

# Open in browser
open http://localhost:3000

Step 3: Deploy ArchiveBox

ArchiveBox is a self-hosted web archiving solution. Python-based, with a more complex setup involving multiple volumes and environment variables.

mkdir ~/archivebox && cd ~/archivebox
stacker init --from-github ArchiveBox/ArchiveBox --with-ai --force

# Review the generated stacker.yml
cat stacker.yml

# Generate secrets and deploy
cp .env.example .env
./scripts/generate-secrets.sh
stacker deploy --target local

Notice how Stacker handled ArchiveBox's complexity: multiple volumes for data persistence, the correct entrypoint command, and all the environment variables pulled from the project's documentation.

Step 4: Deploy Floci (AWS Local Emulator)

Floci emulates AWS services locally. It's a complex Go project with Docker-in-Docker, multiple port ranges, and volume mounts for the Docker socket.

mkdir ~/floci && cd ~/floci
stacker init --from-github floci-io/floci --with-ai --force

Stacker handles the complexity automatically:

  • Detects the Dockerfile at the project root
  • Reads the docker-compose.yml to find port mappings (4566, plus the port ranges)
  • Extracts all 7 FLOCI_* environment variables from the compose file
  • Identifies the Docker socket volume mount (/var/run/docker.sock)
  • Generates a clean stacker.yml with the app as app.image: floci/floci:latest

Step 5: Understanding the Generated Config

Let's look at what Stacker produced for Umami. The stacker.yml will look something like:

name: umami
deploy:
  target: local
app:
  type: node
  path: .
  ports:
    - "3000:3000"
  environment:
    DATABASE_URL: "postgresql://umami:${DB_PASSWORD}@postgres:5432/umami"
    HASH_SALT: "${HASH_SALT}"
services:
  - name: postgres
    image: postgres:16-alpine
    ports:
      - "127.0.0.1:5432:5432"
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: "${DB_PASSWORD}"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: "CMD-SHELL pg_isready -U umami -d umami"
      interval: 5s
      timeout: 2s
      retries: 10
volumes:
  postgres_data: {}
proxy:
  type: none
  auto_detect: false

Key things Stacker got right without any manual input:

  • Correct app type: Node.js detected from package.json
  • Database service: PostgreSQL extracted from docker-compose.yml
  • Healthcheck: pg_isready automatically added
  • Port isolation: PostgreSQL bound to 127.0.0.1 — not exposed externally
  • Volume persistence: Named volume for database data
  • Secret handling: All passwords use ${VAR_NAME} syntax, never hardcoded

Step 6: Customizing the Configuration

Edit stacker.yml to customize your deployment:

# Add a reverse proxy with SSL
proxy:
  type: nginx
  auto_detect: true
  domains:
    - domain: umami.yourdomain.com
      ssl: auto
      upstream: app:3000

# Enable monitoring
monitoring:
  status_panel: true
  healthcheck:
    endpoint: /api/health
    interval: 30s

# Add AI troubleshooting for failed deployments
ai:
  enabled: true
  provider: ollama

After editing, redeploy:

stacker config validate
stacker deploy --target local

Step 7: Deploying to Production

Once your stack works locally, deploy it to your own server:

# Option A: Your own server
stacker config setup server
# Enter: host IP, SSH user, SSH key path
stacker deploy --target server

# Option B: Cloud provider (Hetzner, DO, AWS, etc.)
stacker config setup cloud
# Interactive wizard: choose provider, region, instance size
stacker deploy --target cloud

Stacker provisions the server, installs Docker, deploys your stack, configures the reverse proxy with SSL, and installs the Status Panel agent for ongoing monitoring — all from the CLI.

What to Do When Things Go Wrong

AI generation fails

# Stacker falls back to template-based detection automatically.
# Or try a different AI provider:
stacker init --from-github owner/repo --with-ai \
  --ai-provider openai --ai-api-key sk-... --force

Deployment fails

# Check logs
stacker logs

# With AI troubleshooting enabled in stacker.yml:
stacker ai ask "why is my postgres container crashing?" --context ./stacker.yml

Port conflict

# Edit stacker.yml to change the host port:
app:
  ports:
    - "3001:3000"  # Changed host port from 3000 to 3001

# Redeploy
stacker deploy --target local

Need to regenerate

# Use --force to overwrite existing files
stacker init --from-github owner/repo --with-ai --force

Beyond the Tutorial

Stacker does much more than deploy from GitHub:

  • Visual Stack Builder: Drag-and-drop interface for composing multi-service stacks at try.direct
  • 56+ pre-built stacks: One-click deploy for n8n, Supabase, Ghost, Grafana, Open WebUI, and more
  • Pipes: Container-to-container data flows (like self-hosted Zapier)
  • CI/CD integration: stacker ci export --platform github generates GitHub Actions workflows
  • Vault secrets: Remote secret storage and injection for production deployments

Key Takeaways

  • Any GitHub repo with a docker-compose.yml can be deployed in two commands
  • --with-ai dramatically improves config quality by reading README, compose, and source
  • Healthchecks, port isolation, and secret handling are automatic
  • The same stacker.yml works identically on local, server, and cloud targets
  • You own the infrastructure — Stacker just manages the deployment
  • Everything is open source (MIT) on GitHub

Try It Yourself

Deploy this stack or browse pre-built templates in the marketplace. Your first deployment is always free.