A comprehensive GitHub Action for deploying applications to baremetal servers via SSH. This action supports three deployment modes: baremetal (direct to server), Docker, and Kubernetes.
- 🔐 Secure SSH Authentication - Support for SSH keys or password authentication
- 🎯 Multiple Deployment Types - Choose between baremetal, Docker, or Kubernetes deployments
- 🐳 Docker Support - Automatic Docker and Docker Compose installation
- ☸️ Kubernetes Support - Automatic k3s, kubectl, and helm installation
- 🔧 Auto Dependency Installation - Installs git and other required tools
- 🏷️ Registry Support - Supports GHCR, Docker Hub, and AWS ECR
- 🌿 Branch Management - Automatic branch switching based on environment
name: Deploy with MetalDeploy
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy with MetalDeploy
uses: OpsGuild/MetalDeploy@v1
with:
git_url: ${{ secrets.GIT_URL }}
git_auth_method: token
git_token: ${{ secrets.GITHUB_TOKEN }}
git_user: ${{ github.actor }}
remote_host: ${{ secrets.REMOTE_HOST }}
ssh_key: ${{ secrets.SSH_PRIVATE_KEY }}
deployment_type: docker
environment: prodname: Deploy with MetalDeploy
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy with MetalDeploy
uses: OpsGuild/MetalDeploy@v1
with:
git_url: https://github.com/username/repo.git
git_token: ${{ secrets.GITHUB_TOKEN }}
git_user: ${{ github.actor }}
remote_host: ${{ secrets.REMOTE_HOST }}
remote_user: deploy
ssh_key: ${{ secrets.SSH_PRIVATE_KEY }}
environment: prod
registry_type: dockerhub
registry_username: ${{ secrets.DOCKERHUB_USERNAME }}
registry_password: ${{ secrets.DOCKERHUB_PASSWORD }}
profile: production| Input | Description | Required | Default |
|---|---|---|---|
git_url |
Git repository URL to clone and deploy | ✅ | - |
git_auth_method |
Git authentication method: token, ssh, or none | ❌ | token |
git_token |
GitHub token for authentication (required if git_auth_method is token) | ❌ | - |
git_user |
GitHub username (required if git_auth_method is token) | ❌ | - |
git_ssh_key |
SSH private key for Git authentication (required if git_auth_method is ssh) | ❌ | - |
deployment_type |
Deployment type: baremetal, docker, or k8s | ❌ | docker |
remote_host |
SSH remote host IP or domain | ✅ | - |
remote_user |
SSH remote user | ❌ | root |
remote_dir |
Remote directory path for deployment | ❌ | /home/{remote_user} |
ssh_key |
SSH private key for authentication | ❌ | - |
remote_password |
SSH password (if not using SSH key) | ❌ | - |
environment |
Deployment environment (dev, staging, prod) | ❌ | dev |
registry_type |
Docker registry type (ghcr, dockerhub, ecr) | ❌ | ghcr |
registry_username |
Docker registry username (for dockerhub) | ❌ | - |
registry_password |
Docker registry password (for dockerhub) | ❌ | - |
aws_region |
AWS region (for ECR) | ❌ | - |
aws_account_id |
AWS account ID (for ECR) | ❌ | - |
profile |
Docker Compose profile to use (for docker deployment) | ❌ | - |
baremetal_command |
Command to run for baremetal deployment (e.g., "make deploy") | ❌ | - |
k8s_manifest_path |
Path to Kubernetes manifest file or directory | ❌ | - |
k8s_namespace |
Kubernetes namespace to deploy to | ❌ | default |
use_sudo |
Use sudo for commands (true/false). Some system commands may still require sudo | ❌ | false |
| Output | Description |
|---|---|
deployment_status |
Deployment status (success/failed) |
remote_hostname |
Hostname of the remote server |
Deploy directly to the server without Docker or Kubernetes. Perfect for simple applications or when you want full control.
Usage:
deployment_type: baremetal
baremetal_command: make deploy # Optional: custom command to runDefault Behavior:
- If
baremetal_commandis specified, runs that command - Otherwise, looks for
deploy.shand runs it - If no
deploy.sh, looks forMakefileand runsmake {environment} - If none found, requires
baremetal_commandto be specified
Example:
- name: Deploy with MetalDeploy
uses: OpsGuild/MetalDeploy@v1
with:
deployment_type: baremetal
baremetal_command: "npm install && npm run build && pm2 restart app"
# Or let it auto-detect: make dev, make staging, make prodDeploy using Docker Compose. The action automatically installs Docker and Docker Compose.
Usage:
deployment_type: docker
profile: production # Optional: use Docker Compose profilesExample:
- name: Deploy with MetalDeploy
uses: OpsGuild/MetalDeploy@v1
with:
deployment_type: docker
profile: production
registry_type: dockerhub
registry_username: ${{ secrets.DOCKERHUB_USERNAME }}
registry_password: ${{ secrets.DOCKERHUB_PASSWORD }}Requirements: Your repository must have a docker-compose.yml or compose.yml file.
Deploy to Kubernetes using k3s. The action automatically installs k3s, kubectl, and helm.
Usage:
deployment_type: k8s
k8s_manifest_path: k8s/ # Optional: defaults to k8s/, manifests/, or kubernetes/
k8s_namespace: production # Optional: defaults to 'default'Default Behavior:
- Looks for manifests in
k8s/,manifests/, orkubernetes/directories - Or looks for
k8s.yaml,k8s.yml,deployment.yaml, ordeployment.ymlfiles - Creates namespace if it doesn't exist
- Applies all manifests in the specified path
Example:
- name: Deploy with MetalDeploy
uses: OpsGuild/MetalDeploy@v1
with:
deployment_type: k8s
k8s_manifest_path: k8s/
k8s_namespace: production
registry_type: ghcrRequirements: Your repository should have Kubernetes manifest files (YAML) in a k8s/, manifests/, or kubernetes/ directory.
Uses git_user and git_token for authentication.
registry_type: ghcrRequires registry_username and registry_password.
registry_type: dockerhub
registry_username: ${{ secrets.DOCKERHUB_USERNAME }}
registry_password: ${{ secrets.DOCKERHUB_PASSWORD }}Requires aws_region and aws_account_id. The action will use AWS CLI to authenticate.
registry_type: ecr
aws_region: us-east-1
aws_account_id: 123456789012The action automatically installs dependencies based on the deployment type:
All deployments:
- Git
- Python 3 and pip
- Build tools (build-essential, libssl-dev, libffi-dev)
Docker deployments (docker or k8s):
- Docker and Docker Compose
Kubernetes deployments (k8s only):
- kubectl (Kubernetes CLI)
- Helm (Kubernetes package manager)
- k3s (lightweight Kubernetes distribution)
By default, the action doesnt use sudo for commands. You can enable this by setting use_sudo: true:
use_sudo: true # Run commands with sudoNote: Some system-level commands (like apt-get, systemctl, usermod) will still use sudo regardless of this setting. Deployment commands (like docker compose, make, custom scripts) will respect the use_sudo setting.
This is useful when:
- Your SSH user already has necessary permissions
- You're using a non-root user with proper group memberships (e.g., docker group)
- You want to avoid password prompts for sudo
The action supports three methods for authenticating with Git repositories:
Uses HTTPS with a GitHub Personal Access Token or GitHub Actions token:
git_auth_method: token
git_token: ${{ secrets.GITHUB_TOKEN }}
git_user: ${{ github.actor }}Use when:
- Using GitHub Actions (can use
GITHUB_TOKEN) - You have a Personal Access Token
- You prefer HTTPS over SSH
Uses SSH keys for Git operations:
git_auth_method: ssh
git_ssh_key: ${{ secrets.GIT_SSH_KEY }}
# Or use the same key as server SSH:
# git_ssh_key: ${{ secrets.SSH_PRIVATE_KEY }}Use when:
- You have deploy keys set up
- You prefer SSH authentication
- You want to use the same SSH key for server and Git
Note: The action automatically converts HTTPS URLs to SSH format (e.g., https://github.com/user/repo.git → git@github.com:user/repo.git)
For public repositories only:
git_auth_method: noneUse when:
- Repository is public
- No authentication needed
- Production: Automatically uses
mainormasterbranch - Other environments: Uses the branch matching the environment name (e.g.,
dev,staging)
- Use SSH Keys: Prefer
ssh_keyoverremote_passwordfor better security - Use Secrets: Store all sensitive values in GitHub Secrets
- Limit Permissions: Use a dedicated deployment user with limited sudo permissions
- Rotate Credentials: Regularly rotate SSH keys and tokens
- Remote server must be accessible via SSH
- Sudo access required on remote server (unless using root user)
This action supports the following server operating systems:
- Ubuntu (all LTS and current versions)
- Debian (9+)
- Any other Debian/Ubuntu-based distributions that use:
apt-getpackage managersystemdfor service management- Standard Linux command-line tools
- SSH access (port 22 or custom port)
- Internet connectivity for package installation
- Sufficient disk space for dependencies and your application
- Root or sudo access for system-level operations
Note: The action is optimized for Ubuntu/Debian systems. Other Linux distributions may work but are not officially tested.
This action is built using Fabric (Python library for SSH deployment and system administration) to handle remote server connections and command execution. Fabric provides secure SSH communication and robust command execution capabilities.
Check out the example workflows in the .github/workflows/ directory:
- example-baremetal.yml - Baremetal deployment example
- example-docker.yml - Docker Compose deployment example
- example-k8s.yml - Kubernetes deployment example
This project uses pre-commit to ensure code quality. Install it with:
# Install pre-commit
pip install pre-commit
# Install git hooks
pre-commit installThe hooks will automatically run:
- Code formatting (Black)
- Import sorting (isort)
- Linting (flake8)
- Basic file checks (trailing whitespace, end-of-file, YAML validation, etc.)
This action includes a comprehensive test suite. See tests/README.md for details.
Using Make (recommended):
make install-dev # Install test dependencies
make test # Run all tests
make test-unit # Run only fast unit tests
make test-coverage # Run with coverage reportOr manually:
# Install Poetry (if not already installed)
curl -sSL https://install.python-poetry.org | python3 -
# Install dependencies
poetry install
# Run tests
poetry run pytest
# Run with coverage
poetry run pytest --cov=deploy --cov-report=html- Unit Tests (
tests/test_deploy.py) - Fast tests using mocks, no external dependencies - Integration Tests (
tests/test_integration.py) - Tests requiring real infrastructure (skipped by default)
Tests run automatically in CI on every push and pull request. See tests/README.md for detailed testing documentation.
MIT License - see LICENSE file for details
For issues and feature requests, please open an issue on the GitHub repository.