Skip to content

dreamoutbox/crane

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

210 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

crane — CLI Deployment Tool

crane is a lightweight, zero-Docker deployment tool written in Rust that provisions and deploys application services and high-availability database clusters directly to Ubuntu/Debian VPS nodes over SSH.


Features

  • Zero-Docker App Deploys: Runs your binary directly on remote nodes as systemd template services.
  • High-Availability PostgreSQL: Automated cluster topology with Patroni, etcd as DCS, and HAProxy for smart write/read routing.
  • Built-in Reverse Proxy & SSL: Automatically configures load-balancing and SSL certificates.
  • Automated S3 Backups: Integrated scheduling for database backups (full/incremental) to S3/MinIO.
  • Firewall Setup: Configures firewall for internal cluster ports while exposing public HTTP (80), HTTPS (443), and SSH (22).
  • Cloudflare DNS Sync: Syncs public node IPs to Cloudflare A records automatically.

Quick Start

  1. Install Crane: Compile or download the crane binary and place it in your $PATH.

  2. Scaffold Configuration: Create a crane.toml configuration and .env secrets file in your repository:

    # crane.toml
    
    [[nodes]]
    name = "vps1"
    public_ip = "10.0.0.11"
    internal_ip = "10.0.0.11"
    roles = ["app", "haproxy", "postgres", "redis"]
    user = "crane"
    ssh_ip = "127.0.0.1"
    ssh_port = 2221
    private_key = "keys/id_ed25519"
    sudo_pass = "${SUDO_PASS_VPS1}"
    
    [[nodes]]
    name = "vps2"
    public_ip = "10.0.0.12"
    internal_ip = "10.0.0.12"
    roles = ["app", "haproxy", "postgres", "redis"]
    user = "crane"
    ssh_ip = "127.0.0.1"
    ssh_port = 2222
    private_key = "keys/id_ed25519"
    sudo_pass = "${SUDO_PASS_VPS2}"
    
    [[nodes]]
    name = "vps3"
    public_ip = "10.0.0.13"
    internal_ip = "10.0.0.13"
    roles = ["app", "haproxy", "postgres", "redis"]
    user = "crane"
    ssh_ip = "127.0.0.1"
    ssh_port = 2223
    private_key = "keys/id_ed25519"
    sudo_pass = "${SUDO_PASS_VPS3}"
    
    
    [[users]]
    name = "deployman"
    groups = ["www"]
    ssh_authorized_keys = ["keys/id_ed25519.pub"]
    private_key = "keys/id_ed25519"
    
    
    [app.myapp]
    name = "myapp"
    # Setup Info
    dependencies = ["libssl3", "ca-certificates"]
    # Deploy Info
    deploy_dir = "./demo"
    entrypoint = "./myapp"
    pre_deploy_script = "./before-deploy.sh"
    deploy_user = "deployman"
    port_start = 3000
    port_end = 3100
    # Health Check
    health_check_path = "/health"
    health_check_timeout = 30
    health_check_interval = 2
    # Domain
    domain = "myapp.localhost"
    # Replicas
    instances = 1
    # ENV for myapp
    [app.myapp.env]
    LOG_LEVEL = "debug"
    APP_NAME = "myapp"
    # Databases for myapp
    [[app.myapp2.database]]
    databases = "mydb"
    user = "u1"
    
    [app.myapp2]
    name = "myapp2"
    # Setup Info
    dependencies = ["libssl3", "ca-certificates"]
    # Deploy Info
    deploy_dir = "./demo"
    entrypoint = "./myapp"
    deploy_user = "deployman"
    port_start = 4000
    port_end = 4100
    # Health Check
    health_check_path = "/health"
    health_check_timeout = 30
    health_check_interval = 2
    # Domain
    domain = "myapp2.localhost"
    # Replicas
    instances = 2
    # ENV for myapp2
    [app.myapp2.env]
    LOG_LEVEL = "debug"
    APP_NAME = "myapp2"
    # Databases for my app2
    [[app.myapp2.database]]
    databases = "mydb"
    user = "u1"
    
    
    [db.postgres]
    enabled = true
    version = "17"
    replica_pass = "replica"
    
    [db.postgres.backup]
    full_backup_every = "1h"
    incremental_backup_every = "15m"
    
    [db.postgres.mydb]
    name = "mydb"
    
    [[db.postgres.users]]
    # state = "present" / "absent"
    state = "present"
    user = "u1"
    password = "u1"
    databases = ["mydb"]
    
    [[db.postgres.users]]
    state = "present"
    user = "u2"
    password = "u2"
    databases = ["mydb"]
    
    
    [backup.s3]
    bucket = "crane1"
    region = "us-east-1"
    endpoint = "http://s3:9000"
    access_key_id = "${S3_ACCESS_KEY_ID}"
    secret_access_key = "${S3_SECRET_ACCESS_KEY}"
    
    
    [domain]
    provider = "cloudflare"
    domain_name = "localhost"
    token = "${CLOUDFLARE_TOKEN}"
  3. Deploy: Make sure environment variables referenced in crane.toml (such as SUDO_PASS_VPS1, SUDO_PASS_VPS2, SUDO_PASS_VPS3, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, and CLOUDFLARE_TOKEN) are set in your current shell or defined in your .env file before deploying:

    crane deploy

How It Works

  1. Multiplexed SSH: Crane opens a single multiplexed master SSH connection (ControlMaster) to each node.
  2. Firewall Provisioning: configures the nodes firewall to only expose ports 22, 80, and 443 publicly, and fully whitelist inter-node communication.
  3. Database Topology: Configures Patroni and etcd clusters on nodes with the postgres role.
  4. App Delivery: Compresses the application, transfers it over SCP, extracts it, merges environmental variables, starts the systemd service instances, and polls health checks.
  5. Reverse Proxying: Hooks up HAProxy/Traefik reverse proxies to distribute incoming public traffic across the running instances.

Basic Commands

Command Description
crane deploy Deploy the application and database cluster.
crane status Display cluster status, node health, and app instances.
crane logs <app> Stream application standard output/error logs.

PostgreSQL Management Commands

Command Description
crane pg status Inspect the PostgreSQL active primary/replica topologies and replication lag.
crane pg promote --node <host> Force-promote a specific node to primary database leader.
crane pg backup <full|incr> Trigger a manual full or incremental cluster database backup to S3.
crane pg list List available database backups.
crane pg restore <backup_id> [--pitr <TIME>] Restore the database state from an S3 backup ID. with Point-in-time recovery support. --pitr <YYYY-MM-DD HH:MM:SS>

Developer Setup

Prerequisites

  • Rust (latest stable edition)
  • Docker and Docker Compose (to run the simulated VPS setup)

Setting Up the Dev Environment

  1. Start the Simulated VPS Cluster:

    # Install required packages for dev
    ./devsetup.sh
    
    # Setup dev SSH keys
    ./setup-ssh.sh
    
    # Setup docker for simulate VPS servers setup
    ./setup-docker.sh
  2. Run Code Verification: Ensure you use cargo nextest to execute tests. Run single test suites at a time to prevent performance bottlenecks:

    cargo nextest run --test deploy -- test_single_deploy --nocapture

Contributing

Contributions are highly welcome! Feel free to open issues or submit pull requests. For large architectural changes, please open an issue first to discuss the design.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors