{"id":34571053,"url":"https://github.com/skssmd/graft","last_synced_at":"2026-01-20T16:01:23.040Z","repository":{"id":330448646,"uuid":"1120010014","full_name":"skssmd/Graft","owner":"skssmd","description":"A simple agentless deployment engine that extends the Docker Compose workflow to cloud infrastructure via SSH. Graft enables native remote management of AWS, GCP, and VPS instances with no agent installs or server-side overhead required. With features like DNS Configurations, Rollbacks, CI/CD Workflow","archived":false,"fork":false,"pushed_at":"2026-01-14T08:41:48.000Z","size":31864,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-16T10:26:52.803Z","etag":null,"topics":["aws-ec2","cli-remote-commands","cli-tool","deployment","docker-compose","documented","easy-deployment","google-cloud","reverse-proxy","server-manager","ssh","vps-server"],"latest_commit_sha":null,"homepage":"https://graftdocs.vercel.app","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skssmd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-20T09:46:37.000Z","updated_at":"2026-01-14T08:41:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/skssmd/Graft","commit_stats":null,"previous_names":["skssmd/graft"],"tags_count":33,"template":false,"template_full_name":null,"purl":"pkg:github/skssmd/Graft","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skssmd%2FGraft","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skssmd%2FGraft/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skssmd%2FGraft/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skssmd%2FGraft/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skssmd","download_url":"https://codeload.github.com/skssmd/Graft/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skssmd%2FGraft/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28606288,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T14:45:23.139Z","status":"ssl_error","status_checked_at":"2026-01-20T14:44:16.929Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws-ec2","cli-remote-commands","cli-tool","deployment","docker-compose","documented","easy-deployment","google-cloud","reverse-proxy","server-manager","ssh","vps-server"],"created_at":"2025-12-24T09:35:46.213Z","updated_at":"2026-01-20T16:01:23.033Z","avatar_url":"https://github.com/skssmd.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"```text\r\n ██████  ██████   █████  ███████ ████████ \r\n██       ██   ██ ██   ██ ██         ██    \r\n██   ███ ██████  ███████ █████      ██    \r\n██    ██ ██   ██ ██   ██ ██         ██    \r\n ██████  ██   ██ ██   ██ ██         ██    \r\n```\r\n\r\n# Graft 🚀\r\n\r\n**Manage remote Docker Compose projects like they're running on localhost.**\r\n\r\nGraft is a deployment tool for developers who know Docker Compose and want to keep using it in production. No new DSL to learn, no complex YAML configurations, no agent installations—just your familiar `docker-compose.yml` and some SSH magic.\r\n\r\nBuilt for the solo developer rotating between cloud free tiers and the small team that finds Kubernetes overkill. If you can run `docker compose up` locally, you can deploy to production with Graft.\r\n\r\n\u003e [!IMPORTANT]\r\n\u003e Use a **clean server** for initial setup. Graft configures Docker, Traefik, and networking automatically, which may conflict with existing manual configurations.\r\n\r\n---\r\n\r\n## 🎯 What Problem Does This Solve?\r\n\r\n**The typical deployment journey:**\r\n1. Docker Compose works great locally\r\n2. Time to deploy to production\r\n3. Options: Learn Kubernetes, pay for managed platforms, or SSH in manually\r\n4. All of these suck in different ways\r\n\r\n**Graft's approach:**\r\n```bash\r\n# Local development\r\ndocker compose up -d --pull always\r\n\r\n# Production with Graft (same commands)\r\ngraft up -d --pull always\r\n```\r\n\r\nSame workflow. Different server. That's it.\r\n\r\n**Graft is a simple tool for simple use cases.** Sometimes you don't need Kubernetes-level features—you just need to put your service online as fast as possible, make sure it stays healthy, and interact with it without verbose steps. No manifest sprawl, no cluster management.\r\n\r\n---\r\n\r\n## 🏗️ How It Works\r\n\r\n**Core concept:** Graft extends Docker Compose to remote servers over SSH.\r\n\r\nEvery Graft project has:\r\n- Your existing `docker-compose.yml`\r\n- A `graft-compose.yml` (Graft-specific context—basically a smarter docker-compose that Graft reads)\r\n- A `.graft` folder (stores server config, project context, and all the boring infrastructure details)\r\n- SSH access to a server\r\n\r\nWhen you run `graft init`, it:\r\n1. Attaches to your server (or registers a new one if this is your first rodeo)\r\n2. Checks if the server is ready—if not, it installs Docker, Traefik, configures networking, and basically does all the boring sysadmin stuff you'd rather not do\r\n3. Asks you which deployment mode you want (or skip it, you can configure later when you've had your coffee)\r\n4. Installs grafthook if needed (for webhook-based deployments—it's like a doorbell for your CI/CD)\r\n5. Generates a `graft-compose.yml` boilerplate because blank files are scary\r\n\r\nWhen you run `graft sync`, it:\r\n1. Checks your mode and project context (Graft remembers which project belongs to which server—better memory than you after a long weekend)\r\n2. Updates or generates Dockerfiles based on your context (smart templating, not just copy-paste)\r\n3. Extracts environment variables from `graft-compose.yml` into a separate `.env` file and wires it to your `docker-compose.yml` (because mixing config and secrets is a recipe for accidentally committing API keys)\r\n4. Generates a GitHub Actions workflow that actually works—with grafthook integration, proper secrets handling, and zero additional configuration needed (assuming your `graft-compose.yml` isn't a disaster)\r\n5. Asks nicely if you want to send environment variables directly to the server (secure transfer, not shouting them over SSH)\r\n6. Syncs your source code based on mode—rsync for direct modes, or politely asks Git to handle it for CI/CD modes\r\n\r\nThen you manage it like localhost: `graft ps`, `graft logs`, `graft restart frontend`—all the Docker Compose commands you already know.\r\n\r\n---\r\n\r\n## ✨ Key Features\r\n\r\n### Docker Compose Passthrough (The Main Event 🎪)\r\nThis is where Graft really shines: **any Docker Compose command works on remote servers, exactly as it does locally.**\r\n\r\n```bash\r\ngraft ps                    # See what's running\r\ngraft logs backend -f       # Follow logs in real-time\r\ngraft restart frontend      # Restart a service\r\ngraft up -d                 # Start services detached\r\ngraft down                  # Stop everything\r\ngraft pull                  # Pull latest images\r\ngraft build --no-cache      # Rebuild from scratch\r\n```\r\n\r\n**One-liner exec/run commands work perfectly:**\r\n```bash\r\ngraft exec backend ls -la              # Run single commands\r\ngraft exec backend cat /app/config.yml # Read files\r\ngraft run alpine echo \"hello\"          # Quick throwaway commands\r\n```\r\n\r\n**Automatic Dns Mapping for Cloudflare based DNSs:**\r\n```bash\r\ngraft map  #Automatically detects domains by service and sets DNS \r\n```\r\n**Easy Rollback to previous deployments:**\r\n```bash\r\ngraft rollback  #Display previous deployments and allow you to rollback to any of them\r\ngraft rollback config #Set up how many versions to keep\r\n``` \r\n\r\n**Important caveat:** Interactive sessions (like `graft exec -it backend bash`) don't work due to SSH-in-SSH limitations. For that, use `graft -sh` to drop into a proper SSH session first, then run your Docker commands there.\r\n\r\n**All your muscle memory still works.** If you know Docker Compose, you know Graft. The only difference is your services are running on a server in some datacenter instead of melting your laptop's CPU.\r\n\r\n### Deployment Modes\r\nChoose how you want to deploy (you can switch anytime—commitment issues are valid):\r\n\r\n**Direct mode** (no Git required):\r\n- **Direct sync**: Rsync your code to the server, server builds images locally. Fast iteration, perfect for \"just ship it\" moments.\r\n\r\n**Git-based modes** (proper CI/CD for people who like feeling professional):\r\n- **GitHub Actions + GHCR**: Auto-generates workflow, builds images in the cloud, pushes to GitHub Container Registry, deploys via webhook. The full adult developer experience.\r\n- **GitHub Actions + server build**: Triggers your server to pull from repo and build there. For when you trust your server's CPU more than GitHub's runners.\r\n- **Git manual**: Sets up the Git integration, but you're in control of when to actually deploy. Trust issues mode.\r\n\r\n**The workflow generation is legitimately impressive:** Point Graft at your compose file, tell it your mode, and it writes a production-ready GitHub Actions workflow with grafthook integration, secrets management, image cleanup, and zero debugging needed. No more copying workflows from StackOverflow and hoping for the best.\r\n\r\n### Multi-Project \u0026 Server Management\r\n**Built for managing multiple clients, projects, and servers without losing your mind:**\r\n- **Project contexts**: `graft -p project1 ps` - Graft remembers which project belongs to which server. You don't have to.\r\n- **Service-level control**: `graft -p project1 logs api` - Target specific services within projects\r\n- **Server registry**: Manage multiple servers without juggling SSH config files or post-it notes\r\n- **One-command DNS migration**: `graft dns map` - Point your Cloudflare DNS at the current server. Works great for rotating between cloud free tiers when you inevitably hit the limits.\r\n- **Remote shell**: `graft -sh` - Drop into an SSH session when you need to dig around manually (we won't judge)\r\n\r\nWhen you have 5 clients with 3 projects each across different servers, Graft handles the context switching so you can focus on the actual work.\r\n\r\n### Infrastructure Automation\r\n- **Traefik reverse proxy**: Auto-configured with SSL via Let's Encrypt\r\n- **Shared services**: Optional Postgres/Redis instances shared across projects\r\n- **DNS automation**: Update Cloudflare DNS records automatically on deployment\r\n- **Network management**: Docker networks created and configured per project\r\n\r\n### Migration Friendly\r\nBuilt for rotating between cloud providers:\r\n- Quick server initialization (5 minutes from fresh server to deployed)\r\n- DNS sync on migration\r\n- Project export/import\r\n- Works with AWS, GCP, DigitalOcean, any VPS with SSH\r\n\r\n---\r\n\r\n## 🛠️ Installation\r\n\r\n### Linux\r\n```bash\r\ncurl -sSL https://raw.githubusercontent.com/skssmd/Graft/main/bin/install.sh | sh\r\n```\r\n\r\n### Windows\r\n```powershell\r\npowershell -ExecutionPolicy ByPass -Command \"iwr -useb https://raw.githubusercontent.com/skssmd/Graft/main/bin/install.ps1 | iex\"\r\n```\r\n\r\n**Or via WinGet:**\r\n```bash\r\nwinget install graft\r\n```\r\n\r\n### From Source\r\n```bash\r\ngit clone https://github.com/skssmd/Graft\r\ncd Graft\r\ngo build -o graft cmd/graft/main.go\r\n```\r\n\r\n**Requirements:** Go 1.24+, SSH access to a Linux server, Docker (installed automatically)\r\n\r\n---\r\n\r\n## 🚀 Quick Start\r\n\r\n```bash\r\n# 1. Initialize project (adds new server or selects existing)\r\ngraft init\r\n# Choose deployment mode from interactive prompt\r\n# (or change later with: graft mode)\r\n\r\n# 2. Edit graft-compose.yml if needed\r\n\r\n# 3. Deploy\r\ngraft sync\r\n\r\n# 4. Manage like localhost\r\ngraft ps                    # Check status\r\ngraft logs backend          # View logs\r\ngraft restart frontend      # Restart service\r\ngraft map #automatically updates cloudflare dns records\r\ngraft rollback #roll back to previous versions\r\n```\r\n\r\n**That's it.** Your project is running on the server, managed via familiar commands.\r\n\r\n---\r\n\r\n## 📖 Documentation\r\n\r\n**Full command reference:** [COMMANDS.md](COMMANDS.md)\r\n\r\n**Common workflows:**\r\n\r\n```bash\r\n# Deploy with automatic GitHub Actions CI/CD\r\ngraft init                          # Select git-images mode from prompt\r\ngraft sync                          # Generates workflow, pushes to GitHub\r\n\r\n# Change deployment mode\r\ngraft mode                          # Interactive mode selection\r\n\r\n# Switch between projects\r\ngraft -p project1 logs              # Project1 logs\r\ngraft -p project1 logs api          # Specific service logs\r\ngraft -p project2 restart           # Restart project2\r\n\r\n# DNS management (Cloudflare)\r\ngraft dns map                       # Update DNS to point to current server\r\n\r\n# Server management\r\ngraft registry ls                   # List all servers\r\ngraft registry add prod user@ip     # Add new server\r\n\r\n# Direct server access\r\ngraft -sh                           # SSH session\r\ngraft exec backend cat /app/log.txt # One-liner commands work\r\n```\r\n\r\n---\r\n\r\n## 🎯 Use Cases\r\n\r\n**Perfect for:**\r\n- Solo developers with side projects who need to ship fast\r\n- Small teams not ready for Kubernetes (and probably don't need it)\r\n- Agencies or freelancers juggling multiple clients and projects across different servers—Graft keeps track so you don't have to\r\n- Migrating between cloud providers (free tier rotation is a valid business strategy - i think :P)\r\n- Rapid prototyping and iteration without deployment overhead\r\n- Projects that outgrew localhost but don't need enterprise orchestration\r\n\r\n**Not for:**\r\n- Multi-region deployments\r\n- Multi-server deployments\r\n---\r\n\r\n## 🏷️ What Makes This Different\r\n\r\n**vs Dokku/CapRover:** No web UI, pure CLI. More flexible deployment modes. Better for managing multiple projects across multiple servers.\r\n\r\n**vs Railway/Render:** Self-hosted. No vendor lock-in. Works anywhere you have SSH. No monthly bills that scale with your success.\r\n\r\n**vs Manual Deployment:** Automated setup, reverse proxy, DNS, CI/CD generation, multi-project management. All the boring infrastructure work is handled.\r\n\r\n---\r\n\r\n## 🔮 Roadmap\r\n\r\nPlanned features:\r\n- Dev/prod environment separation\r\n- Slack/Discord notifications\r\n- Health checks and monitoring\r\n\r\nSee the full roadmap in issues or check the pinned discussion.\r\n\r\n---\r\n\r\n## 🤝 Contributing\r\n\r\nGraft is open source and contributions are welcome. If you're using it and something breaks or could be better, open an issue.\r\n\r\n**Before building new features:** Check if it's on the roadmap or open an issue to discuss. Graft intentionally stays simple—feature requests are evaluated against \"does this solve a common problem simply?\"\r\n\r\n---\r\n\r\n## 📝 License\r\n\r\nMIT License - see [LICENSE](LICENSE) file.\r\n\r\n---\r\n\r\n## 💬 Support \u0026 Community\r\n\r\n- **Issues**: Bug reports and feature requests\r\n- **Discussions**: Questions, showcase your projects, general chat\r\n- **GitHub**: Star if you find it useful, helps others discover it\r\n\r\n---\r\n\r\n## ⚠️ Disclaimer\r\n\r\nGraft is a tool for developers who understand Docker and servers. It automates deployment, it doesn't make deployment decisions for you. \r\n\r\nBuilt by a developer tired of manually SSH-ing into servers to check logs. Might be useful to others in the same boat.\r\n\r\n---\r\n\r\n**TL;DR:** Docker Compose commands that work on remote servers. Deploy your projects without learning Kubernetes or paying for managed platforms. Works with any server you can SSH into.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskssmd%2Fgraft","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskssmd%2Fgraft","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskssmd%2Fgraft/lists"}