A cloud infrastructure management CLI for automated deployment and High Availability (HA) cluster orchestration. Dynia simplifies cloud infrastructure provisioning with Docker-based services, automated DNS configuration, HTTPS certificates, and failover management. Currently supports DigitalOcean with extensible architecture for additional cloud providers.
- 🔗 Reserved IP Management: Stable public IP address for cluster access
- ⚡ Elastic Scaling: Start with 1 node, scale to N nodes seamlessly
- 🔄 Automatic Failover: keepalived-based failover with priority management
- 🎯 Host-Based Routing: Multiple services behind a single IP using Caddy proxy
- 🏷️ Two-Word Node IDs: Human-friendly node identification (e.g.,
brave-panda,misty-owl)
- 🔑 SSH Key Management: Automated SSH key generation and cloud provider integration
- 🖥️ Cloud VM Provisioning: One-command cloud VM creation (currently DigitalOcean Ubuntu 22.04)
- 🌐 DNS Automation: Automatic DNS A record creation and propagation (currently Cloudflare)
- 🔒 HTTPS Certificates: Automated SSL/TLS certificate generation via Caddy
- 🐳 Docker Infrastructure: Containerized services with reverse proxy and health monitoring
- 🔍 Two-Sided Health Checks: Internal container validation + public accessibility testing
- 🔄 Intelligent Recovery: Progressive state saving and automatic repair capabilities
- ⚡ Built-in Resilience: Retry logic for transient failures and network issues
- 📊 Infrastructure Monitoring: Comprehensive cluster and node status reporting
- Cloud Provider Account: Currently requires DigitalOcean for VM provisioning
- DNS Provider Account: Currently requires Cloudflare for DNS management
- Domain: A domain registered and configured with your DNS provider
- Node.js 22+: For running the CLI tool
# Clone the repository
git clone https://github.com/thaitype/dynia.git
cd dynia
# Install dependencies
pnpm install
# Build the project
pnpm build
# Navigate to example directory
cd examples/basicCreate a .env file in your project directory with provider configurations:
# Cloud Provider Configuration (DigitalOcean)
DYNIA_DO_TOKEN=dop_v1_your_digitalocean_token_here
# DNS Provider Configuration (Cloudflare)
DYNIA_CF_TOKEN=your_cloudflare_api_token_here
DYNIA_CF_ZONE_ID=your_cloudflare_zone_id_here
# SSH Key Configuration
DYNIA_SSH_KEY_ID=your_ssh_key_id_hereCurrent provider defaults (DigitalOcean):
- Region:
nyc3(New York) - VM Size:
s-1vcpu-1gb(1 vCPU, 1GB RAM) - Image:
ubuntu-22-04-x64(Ubuntu 22.04 LTS)
# Create SSH key with default name 'dynia'
pnpm dynia ssh create
# Create SSH key with custom name
pnpm dynia ssh create --key-name myproject
# Recreate existing SSH key
pnpm dynia ssh create --force
# Create key and display environment variable
pnpm dynia ssh create --output-env# Show all SSH keys in your DigitalOcean account
pnpm dynia ssh list# Create a new HA cluster (starts with 1 node)
pnpm dynia cluster create-ha --name myapp --base-domain example.com
# Create cluster in specific region
pnpm dynia cluster create-ha --name webapp --base-domain mydomain.com --region sgp1 --size s-2vcpu-2gb# Show all clusters
pnpm dynia cluster list# Prepare all nodes in cluster
pnpm dynia cluster prepare myapp
# Force re-preparation of all nodes
pnpm dynia cluster prepare myapp --force
# Prepare nodes in parallel (faster)
pnpm dynia cluster prepare myapp --parallel# Check cluster health only
pnpm dynia cluster repair-ha myapp --check-only
# Repair cluster infrastructure
pnpm dynia cluster repair-ha myapp --force# Destroy cluster with confirmation prompt
pnpm dynia cluster destroy myapp
# Force destroy without confirmation
pnpm dynia cluster destroy myapp --confirm# Add one node to cluster
pnpm dynia cluster node add --cluster myapp
# Add multiple nodes
pnpm dynia cluster node add --cluster myapp --count 3# Show all nodes in a cluster
pnpm dynia cluster node list --cluster myapp# Prepare specific node infrastructure
pnpm dynia cluster node prepare --cluster myapp --node brave-panda
# Force re-preparation of node
pnpm dynia cluster node prepare --cluster myapp --node brave-panda --force# Make a node active (move Reserved IP)
pnpm dynia cluster node activate --cluster myapp --node misty-owl# Remove node with confirmation prompt
pnpm dynia cluster node remove --cluster myapp --node brave-panda
# Force remove without confirmation
pnpm dynia cluster node remove --cluster myapp --node brave-panda --confirm# Show all Reserved IPs and their assignment status
pnpm dynia cluster reserved-ip list
# Filter by region
pnpm dynia cluster reserved-ip list --region nyc3
# Show only unassigned IPs
pnpm dynia cluster reserved-ip list --status unassigned# Assign Reserved IP to specific node
pnpm dynia cluster reserved-ip assign --cluster myapp --node brave-panda# Deploy placeholder service for testing
pnpm dynia cluster deployment create --name myapp --placeholder
# Deploy custom application with domain
pnpm dynia cluster deployment create --name myapp --compose ./app.yml --domain myapp-api.example.com
# Deploy with custom health check path
pnpm dynia cluster deployment create --name myapp --compose ./app.yml --domain myapp-web.example.com --health-path /healthFor backward compatibility, single-node commands are still available:
# Create a single node (legacy mode)
pnpm dynia node create --name webserver
# Create numbered node
pnpm dynia node create --name api --number 1
# Create node with custom health check path
pnpm dynia node create --name app --health-path /health# Show all single nodes and their status
pnpm dynia node list# Check node status only
pnpm dynia node repair webserver --check-only
# Repair node with confirmation prompt
pnpm dynia node repair webserver
# Force repair without confirmation
pnpm dynia node repair webserver --force# Step 1: Create and upload SSH key to DigitalOcean
pnpm dynia ssh create --output-env
# Step 2: Copy the DYNIA_SSH_KEY_ID to your .env file
echo "DYNIA_SSH_KEY_ID=12345678" >> .env
# Step 3: Create your first HA cluster
pnpm dynia cluster create-ha --name myapp --base-domain example.com
# Step 4: Verify cluster creation
pnpm dynia cluster list
pnpm dynia cluster node list --cluster myapp
# Your cluster is now accessible at the Reserved IP
# You can deploy services to: https://yourservice.example.com# Add additional nodes for high availability
pnpm dynia cluster node add --cluster myapp --count 2
# Verify all nodes are healthy
pnpm dynia cluster node list --cluster myapp
# Test failover by activating a different node
pnpm dynia cluster node activate --cluster myapp --node misty-owl
# Deploy a test service across the cluster
pnpm dynia cluster deployment create --name myapp --placeholder# Deploy your application to the cluster
pnpm dynia cluster deployment create --name myapp --compose ./docker-compose.yml --domain myapp-api.example.com
# The service will be accessible at: https://myapp-api.example.com
# Traffic will be routed to the active node automatically
# Note: Use single-level subdomains for SSL compatibility- Cloud VMs: DigitalOcean Droplets (Ubuntu 22.04 LTS)
- DNS: Cloudflare (A records, SSL certificates)
- Deployment Model: One cloud provider per cluster configuration
AWS: EC2 instances + Route 53 DNSGoogle Cloud: Compute Engine + Cloud DNS- Azure: Virtual Machines + Azure DNS
Dynia uses a pluggable provider architecture - you configure one cloud provider at a time for your deployments. Each cluster uses a single cloud provider, with the flexibility to choose different providers for different projects.
When you create an HA cluster, Dynia automatically provisions:
-
Cloud Infrastructure (DigitalOcean)
- Multiple cloud VMs (Ubuntu 22.04 LTS droplets)
- Reserved/Elastic IP address for cluster access
- Private networking between nodes
- SSH access configured
-
DNS Configuration (Cloudflare)
- A records pointing to cluster IP
- Automated domain routing configuration
-
HA Services on Each Node
- Docker & Docker Compose: Container orchestration
- Caddy Proxy: HTTPS certificates and host-based routing
- keepalived: Automatic failover between nodes
- Health Monitoring: Container and service health checks
-
Security Configuration
- Automatic HTTPS/SSL certificates via Let's Encrypt
- Security headers (HSTS, CSP, etc.)
- Firewall-friendly configuration
- Private networking between nodes
Internet → Cluster IP → Active Node (keepalived) → Caddy → Docker Services
↕ Failover
Standby Nodes → keepalived monitors
Nodes progress through these states:
provisioning: Droplet is being createddroplet-created: DigitalOcean VM is runningdns-configured: DNS record created in Cloudflaredns-ready: DNS propagation verifiedinfrastructure-ready: Docker services deployedactive: All health checks passed, fully operational
- Active: Holds the Reserved IP, receives all traffic
- Standby: Ready to take over if active node fails
- Format:
<adjective>-<animal>(e.g.,brave-panda,misty-owl) - Usage: Friendly identification in commands and logs
- Hostname: Becomes
clustername-nodeid(e.g.,myapp-brave-panda)
# Check overall cluster health
pnpm dynia cluster repair-ha myapp --check-only
# Check individual node health
pnpm dynia cluster node list --cluster myapp
# View Reserved IP assignments
pnpm dynia cluster reserved-ip list# Test failover by switching active nodes
pnpm dynia cluster node activate --cluster myapp --node misty-owl
# Verify the Reserved IP moved to the new node
pnpm dynia cluster reserved-ip list# Scale up: Add more nodes for redundancy
pnpm dynia cluster node add --cluster myapp --count 2
# Scale down: Remove unnecessary nodes
pnpm dynia cluster node remove --cluster myapp --node brave-panda --confirm
# Rebalance: Prepare all nodes after scaling
pnpm dynia cluster prepare myappEnvironment variables for advanced configuration:
# Custom DigitalOcean region (default: nyc3)
DYNIA_DO_REGION=sfo3
# Custom droplet size (default: s-1vcpu-1gb)
DYNIA_DO_SIZE=s-2vcpu-2gb-
Reserved IP Not Assigned
# Check Reserved IP status pnpm dynia cluster reserved-ip list # Manually assign to node pnpm dynia cluster reserved-ip assign --cluster myapp --node brave-panda
-
Node Not Responding
# Check cluster health pnpm dynia cluster repair-ha myapp --check-only # Repair specific node pnpm dynia cluster node prepare --cluster myapp --node brave-panda --force
-
Failover Not Working
# Check keepalived status on nodes pnpm dynia cluster node list --cluster myapp # Force failover to different node pnpm dynia cluster node activate --cluster myapp --node misty-owl
-
SSL Certificate Issues
# SSL "hostname not covered by certificate" error # Cause: Multi-level subdomains not supported by Cloudflare Universal SSL # Solution: Use single-level subdomains # ❌ Problematic: app.cluster.example.com (3 levels) # ✅ Correct: app-cluster.example.com (2 levels) # Check certificate coverage curl -vI https://your-domain.example.com
-
Service Returns 502 Bad Gateway
# Check if Caddy can reach the container # Verify container networking and ports # Check Caddy configuration pnpm dynia cluster deployment create --name myapp --placeholder # View Caddy logs on the node ssh user@node-ip "docker logs dynia-caddy"
-
SSH Connection Timeout
# Verify SSH key is properly configured pnpm dynia ssh list # Check droplet firewall settings in DigitalOcean console
-
DNS Propagation Slow
# DNS can take time - repair will handle it pnpm dynia node repair mynode --force -
Certificate Generation Failed
# Usually resolves automatically with repair pnpm dynia node repair mynode --force -
Container Health Check Failed
# Check detailed status pnpm dynia node repair mynode --check-only
# Enable verbose logging for any command
pnpm dynia cluster create-ha --name debug-cluster --base-domain example.com --verbose
# Dry run mode (test without actual changes)
pnpm dynia cluster node add --cluster myapp --dry-run- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Issues: GitHub Issues
- Documentation: This README and command help (
pnpm dynia --help) - Examples: Check the
examples/directory
Made with ❤️ by the Dynia team