- PowerShell 57.7%
- Shell 42.3%
| apps | ||
| .dockerignore | ||
| .doco-cd.yaml | ||
| .gitignore | ||
| decrypt-sops.ps1 | ||
| decrypt-sops.sh | ||
| encrypt-sops.ps1 | ||
| encrypt-sops.sh | ||
| QUICK-START.md | ||
| README.md | ||
| setup-sops.ps1 | ||
| setup-sops.sh | ||
| SOPS-EXAMPLE.md | ||
doco-cd-example
A sample repository demonstrating how to deploy multiple Docker Compose applications using doco-cd and Forgejo CI/CD runners, with SOPS encryption for secure secrets management.
🚀 Quick Start
New to this project? Start here: QUICK-START.md - Get running in 5 minutes!
Overview
This project showcases the doco-cd pattern for managing multiple containerized applications, each with its own docker-compose.yml and doco-cd.yml configuration file. When changes are pushed to any app folder, Forgejo Actions automatically deploys only the changed applications.
Key Features:
- 🔐 SOPS Encryption - Secure secrets management with age encryption
- 📦 Multi-app Structure - Independent deployment of multiple applications
- 🎯 Selective Deployment - Only changed apps are deployed
- 🔄 Automated CI/CD - Forgejo Actions integration
- 🛡️ Production Ready - Security best practices included
What is doco-cd?
doco-cd is a tool for deploying Docker Compose applications to remote servers via SSH. It simplifies the deployment process by:
- 📦 Copying compose files and dependencies to remote servers
- 🚀 Running docker-compose commands remotely
- 🔄 Managing multiple applications independently
- 🎯 Supporting pre/post deployment hooks
- 🔐 Handling environment variables securely
Project Structure
doco-cd-example/
├── .forgejo/
│ └── workflows/
│ └── doco-cd.yml # Forgejo CI/CD workflow
├── app-a/
│ ├── docker-compose.yml # Nginx web server
│ ├── doco-cd.yml # doco-cd configuration
│ └── html/
│ └── index.html # Static website
├── app-b/
│ ├── docker-compose.yml # Redis + Redis Commander
│ └── doco-cd.yml # doco-cd configuration
├── app-c/
│ ├── docker-compose.yml # PostgreSQL + Adminer
│ ├── doco-cd.yml # doco-cd configuration
│ ├── init.sql # Database initialization
│ └── .env.example # Environment variables template
└── README.md # This file
Sample Applications
App A - Static Web Server
- Service: Nginx serving static HTML
- Port: 8080
- Use case: Simple static website deployment
App B - Redis Cache
- Services: Redis + Redis Commander (web UI)
- Ports: 6379 (Redis), 8081 (Commander)
- Use case: Caching layer with management interface
App C - PostgreSQL Database
- Services: PostgreSQL + Adminer (web UI)
- Ports: 5432 (PostgreSQL), 8082 (Adminer)
- Use case: Database with initialization scripts
Prerequisites
- Docker and Docker Compose installed (locally and on deployment server)
- Forgejo instance with Actions enabled
- Forgejo runner configured and running
- Remote deployment server with SSH access
- doco-cd installed on CI/CD runner (installed automatically in workflow)
Local Testing
Test any application locally before deploying:
# Test app-a
cd app-a
docker-compose up -d
# Visit http://localhost:8080
# Test app-b
cd app-b
docker-compose up -d
# Visit http://localhost:8081 (Redis Commander)
# Test app-c
cd app-c
cp .env.example .env # Edit as needed
docker-compose up -d
# Visit http://localhost:8082 (Adminer)
# Stop any app
docker-compose down
Forgejo CI/CD Setup
1. Configure Forgejo Secrets
Add these secrets to your Forgejo repository settings (Settings → Secrets):
DEPLOY_HOST: Deployment server hostname or IP (e.g.,192.168.1.100)DEPLOY_USER: SSH username (e.g.,deploy)SSH_PRIVATE_KEY: SSH private key for authentication
2. Prepare Deployment Server
On your deployment server:
# Create deployment directories
sudo mkdir -p /opt/apps/{app-a,app-b,app-c}
sudo chown -R deploy:deploy /opt/apps
# Ensure Docker and Docker Compose are installed
docker --version
docker-compose --version
3. How It Works
The Forgejo workflow (.forgejo/workflows/doco-cd.yml):
- Detects changes: Identifies which app folders were modified
- Deploys selectively: Only deploys changed applications
- Uses doco-cd: Runs
doco-cd deployfor each changed app - Runs in parallel: Multiple apps can deploy simultaneously
4. Deployment Trigger
Push changes to the main branch:
# Modify app-a
echo "Updated content" > app-a/html/index.html
git add app-a/
git commit -m "Update app-a content"
git push origin main
# Only app-a will be deployed
doco-cd Configuration
Each app has a doco-cd.yml file that configures deployment:
version: "1"
target:
host: "${DEPLOY_HOST}" # From Forgejo secrets
user: "${DEPLOY_USER}" # From Forgejo secrets
port: 22
path: "/opt/apps/app-a" # Remote deployment path
compose:
file: "docker-compose.yml"
project_name: "app-a"
deploy:
pull: true # Pull images before deploying
build: false # Don't build (use pre-built images)
remove_orphans: true # Clean up old containers
timeout: 300
hooks:
pre_deploy:
- echo "Starting deployment..."
post_deploy:
- echo "Deployment complete!"
Adding New Applications
-
Create app folder:
mkdir app-d -
Add docker-compose.yml:
version: '3.8' services: your-service: image: your-image # ... configuration -
Add doco-cd.yml:
version: "1" target: host: "${DEPLOY_HOST}" user: "${DEPLOY_USER}" path: "/opt/apps/app-d" compose: file: "docker-compose.yml" project_name: "app-d" -
Update workflow: Add a new job in
.forgejo/workflows/doco-cd.ymlfollowing the existing pattern
SOPS Encryption Integration
doco-cd supports SOPS (Secrets OPerationS) for encrypting sensitive data in your deployment files. This allows you to commit encrypted secrets to version control safely.
Why Use SOPS?
✅ Secure: Encrypt secrets before committing to git ✅ Flexible: Supports YAML, JSON, ENV, and INI files ✅ Automatic: doco-cd automatically detects and decrypts SOPS files ✅ Partial encryption: Encrypt only sensitive values, keep structure readable
Quick Setup
-
Run the setup script:
# Linux/macOS chmod +x setup-sops.sh ./setup-sops.sh # Windows PowerShell .\setup-sops.ps1 -
Encrypt your secrets:
# Create a secrets file cd app-a cp secrets.env.example secrets.env # Edit secrets.env with your actual secrets # Encrypt it with SOPS sops encrypt --age <your-age-public-key> secrets.env > secrets.enc.env -
Reference encrypted file in docker-compose.yml:
services: app: env_file: - secrets.enc.env # doco-cd will decrypt this automatically -
Configure CI/CD: Add
SOPS_AGE_KEYto your Forgejo secrets (the private key fromsops_age_key.txt)
Manual SOPS Setup
If you prefer manual setup:
# Install age (encryption tool)
# macOS: brew install age
# Linux: apt install age
# Windows: scoop install age
# Install SOPS
# macOS: brew install sops
# Linux: Download from https://github.com/getsops/sops/releases
# Windows: scoop install sops
# Generate age key pair
age-keygen -o sops_age_key.txt
# Extract public key
grep "public key:" sops_age_key.txt
Encrypting Files
# Encrypt a file
sops encrypt --age <age-public-key> secrets.env > secrets.enc.env
# Edit encrypted file
SOPS_AGE_KEY_FILE=sops_age_key.txt sops edit secrets.enc.env
# Decrypt file (for testing)
sops decrypt secrets.enc.env
Supported File Formats
.yaml,.yml- YAML files.json- JSON files.env- Environment files.ini- INI configuration files
Example: Encrypted Environment File
<augment_code_snippet path="app-a/secrets.env.example" mode="EXCERPT">
# Example secrets file - encrypt this with SOPS
API_KEY=your-api-key-here
DB_PASSWORD=your-database-password
</augment_code_snippet>
After encryption with SOPS, the file becomes unreadable without the decryption key, but doco-cd will automatically decrypt it during deployment.
CI/CD Configuration for SOPS
Update your Forgejo workflow to include the SOPS key:
- name: Deploy app-a
working-directory: app-a
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }} # Add this
run: |
doco-cd deploy -c doco-cd.yml
Important: Never commit sops_age_key.txt to git! It's automatically added to .gitignore.
Troubleshooting
View deployment logs in Forgejo
Check the Actions tab in your Forgejo repository for workflow runs and logs.
SSH connection issues
# Test SSH connection from runner
ssh -i ~/.ssh/id_rsa user@host "echo 'Connection successful'"
View remote container logs
ssh user@host "cd /opt/apps/app-a && docker-compose logs -f"
Manual deployment
# Install doco-cd locally
pip install doco-cd
# Deploy manually
cd app-a
export DEPLOY_HOST=your-host
export DEPLOY_USER=your-user
doco-cd deploy -c doco-cd.yml
SOPS decryption issues
# Test SOPS decryption locally
SOPS_AGE_KEY_FILE=sops_age_key.txt sops decrypt secrets.enc.env
# Verify age key is correct
grep "public key:" sops_age_key.txt
Alternative: External Secrets Providers
While this example uses SOPS encryption, doco-cd also supports external secret management providers:
- AWS Secrets Manager
- Bitwarden Secrets Manager
- 1Password
- Infisical
- OpenBao
See doco-cd External Secrets Wiki for configuration details.
SOPS vs External Providers
| Feature | SOPS | External Providers |
|---|---|---|
| Cost | Free | Varies (some free tiers) |
| Setup | Simple (age key) | Requires service account |
| Offline | ✅ Works offline | ❌ Requires API access |
| Git-friendly | ✅ Encrypted files in repo | ⚠️ References only |
| Rotation | Manual | Often automated |
| Audit logs | Git history | Provider-specific |
| Best for | Small teams, simple setups | Enterprise, compliance needs |
Resources
Documentation
- QUICK-START.md - Get started in 5 minutes
- SOPS-EXAMPLE.md - Detailed SOPS examples
- doco-cd Documentation
- doco-cd Encryption Guide
- doco-cd External Secrets
Tools
Contributing
Feel free to submit issues or pull requests to improve this example repository!
License
MIT