Continuous Integration & Deployment (CI/CD)
MicroFly provides native support for continuous deployment from CI/CD pipelines such as GitHub Actions, GitLab CI, or Forgejo.
You can deploy applications to MicroFly using any of three strategies:
- SSH Deployment (
microfly deploy): Build artifacts inside GitHub Actions and ship them directly via SSH. Recommended for compiled languages (Go, Rust, C++) and Dockerless build matrices. - Signed Webhooks (
POST :8082/api/webhooks/<app>): Trigger MicroFly to pull the latest commit and rebuild. Recommended when you do not want to share SSH credentials with CI. - Direct Git Push: Run
git push microfly mainfrom a CI runner.
Strategy 1: Deploy via SSH & MicroFly CLI (Recommended)
This strategy builds the application inside GitHub Actions, transfers the release bundle to the MicroFly host, and executes microfly deploy.
The full workflow template is located at [.github/workflows/deploy.yml](file:///home/zhair/Documents/tools/microfly/.github/workflows/deploy.yml).
Step 1: Generate an SSH Deployment Keypair
On your local workstation or server:
ssh-keygen -t ed25519 -C "github-actions-deploy" -f id_microfly_deploy -N ""Add the public key (id_microfly_deploy.pub) to ~/.ssh/authorized_keys for the operator account (e.g. pi or ubuntu) on your MicroFly host:
cat id_microfly_deploy.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keysStep 2: Grant Passwordless Sudo for MicroFly Commands
Workload management commands require root or sudo. To allow the deployment user to manage MicroFly without prompting for a password, create /etc/sudoers.d/microfly-deploy on the host:
sudo tee /etc/sudoers.d/microfly-deploy << 'EOF'
pi ALL=(ALL) NOPASSWD: /usr/bin/microfly deploy *, /usr/bin/microfly status *, /usr/bin/microfly preview *
EOF
sudo chmod 0440 /etc/sudoers.d/microfly-deployStep 3: Configure GitHub Repository Secrets
In your GitHub repository, navigate to Settings → Secrets and variables → Actions and add:
MICROFLY_HOST: Hostname or public/tailscale IP (e.g.192.168.1.75orpaas.example.com).MICROFLY_USER: SSH user (e.g.pi).MICROFLY_SSH_KEY: The entire contents of the private key (id_microfly_deploy).
Step 4: Add Workflow Configuration
Create .github/workflows/deploy.yml:
name: Deploy to MicroFly
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Artifacts
run: |
go build -trimpath -ldflags "-s -w" -o server ./cmd/server
- name: Configure SSH Key
uses: webfactory/[email protected]
with:
ssh-private-key: ${{ secrets.MICROFLY_SSH_KEY }}
- name: Add Server to Known Hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -H ${{ secrets.MICROFLY_HOST }} >> ~/.ssh/known_hosts
- name: Deploy to MicroFly
env:
HOST: ${{ secrets.MICROFLY_HOST }}
USER: ${{ secrets.MICROFLY_USER }}
APP: my-app
run: |
STAGING="/tmp/deploy-$APP-${{ github.sha }}"
ssh "$USER@$HOST" "mkdir -p $STAGING"
rsync -avz --delete --exclude '.git' ./ "$USER@$HOST:$STAGING/"
ssh "$USER@$HOST" "sudo microfly deploy --dir $STAGING $APP"
ssh "$USER@$HOST" "rm -rf $STAGING"
ssh "$USER@$HOST" "sudo microfly status $APP"Strategy 2: Ephemeral Pull Request Previews
You can automatically spin up isolated preview environments for every Pull Request:
name: Ephemeral Preview
on:
pull_request:
types: [opened, synchronize, reopened, closed]
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
if: github.event.action != 'closed'
- name: Configure SSH Key
uses: webfactory/[email protected]
with:
ssh-private-key: ${{ secrets.MICROFLY_SSH_KEY }}
- name: Add Server to Known Hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -H ${{ secrets.MICROFLY_HOST }} >> ~/.ssh/known_hosts
- name: Deploy Branch Preview
if: github.event.action != 'closed'
env:
HOST: ${{ secrets.MICROFLY_HOST }}
USER: ${{ secrets.MICROFLY_USER }}
BRANCH: ${{ github.head_ref }}
run: |
STAGING="/tmp/preview-pr-${{ github.event.number }}"
ssh "$USER@$HOST" "mkdir -p $STAGING"
rsync -avz --delete --exclude '.git' ./ "$USER@$HOST:$STAGING/"
ssh "$USER@$HOST" "sudo microfly deploy --dir $STAGING --branch $BRANCH --ttl 48h my-app"
ssh "$USER@$HOST" "rm -rf $STAGING"
- name: Sweep Expired Previews on PR Merge
if: github.event.action == 'closed'
env:
HOST: ${{ secrets.MICROFLY_HOST }}
USER: ${{ secrets.MICROFLY_USER }}
run: |
ssh "$USER@$HOST" "sudo microfly preview sweep"Strategy 3: Deploy via HMAC-Signed Webhook
If you prefer not to manage SSH keys in CI, configure MicroFly's webhook receiver:
- In your application's
app.toml:toml[webhook] enabled = true repository = "owner/my-app" branch = "main" secret = "env:GITHUB_WEBHOOK_SECRET" - Store the webhook secret in MicroFly's encrypted store:bash
printf 'my-strong-shared-secret' | sudo microfly secrets set my-app GITHUB_WEBHOOK_SECRET - In GitHub Actions, trigger the deployment using
curlandopenssl:yaml- name: Trigger MicroFly Webhook env: URL: ${{ secrets.MICROFLY_WEBHOOK_URL }} # e.g. https://api.example.com/api/webhooks/my-app SECRET: ${{ secrets.MICROFLY_WEBHOOK_SECRET }} run: | PAYLOAD="{\"ref\":\"${{ github.ref }}\",\"repository\":{\"full_name\":\"${{ github.repository }}\"}}" SIG="sha256=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $NF}')" curl -fail -X POST "$URL" \ -H "Content-Type: application/json" \ -H "X-GitHub-Event: push" \ -H "X-Hub-Signature-256: $SIG" \ -d "$PAYLOAD"