- Add deployment workflow with test, build, and deploy jobs - Add testing workflow for PRs - Add deployment scripts (deploy, healthcheck, rollback) - Add systemd service configuration - Update Makefile with CI/CD targets - Add comprehensive deployment documentation
24 KiB
GitHub Actions Deployment Guide for CV Site (Go Project)
Target Project:
cv-site(Go application) Repository:github.com/juanatsap/cv-siteDeployment: VM-based deployment (similar to La Porra architecture) Reference: Based on La Porra's GitHub Actions workflows
Table of Contents
- Overview
- Required GitHub Secrets
- Workflow Files Structure
- Main Deployment Workflow
- CDN Integration (Optional)
- Documentation Deployment
- Build Artifacts
- Environment Configuration
- Testing Strategy
- Deployment Checklist
Overview
This guide provides a complete GitHub Actions setup for deploying a Go-based application to a VM server. The workflow is based on La Porra's proven deployment patterns but adapted for Go applications.
Key Components
- CI/CD Pipeline: Automated build, test, and deployment
- Artifact Management: Binary compilation and distribution
- CDN Integration: CloudFlare for static assets (optional)
- Health Checks: Post-deployment validation
- Notifications: Deployment status alerts
Required GitHub Secrets
Configure these secrets in your repository settings (Settings → Secrets and variables → Actions):
Essential Secrets
| Secret Name | Description | Example/Notes |
|---|---|---|
SSH_PRIVATE_KEY |
Private SSH key for VM access | Generate with ssh-keygen -t ed25519 |
SSH_HOST |
VM server hostname or IP | your-vm.example.com or 192.168.1.100 |
SSH_USER |
SSH username for deployment | deployer or ubuntu |
SSH_PORT |
SSH port (if non-standard) | 22 (default) or custom port |
DEPLOY_PATH |
Application directory on VM | /var/www/cv-site or /opt/cv-site |
Optional Secrets (if using CDN)
| Secret Name | Description | Required For |
|---|---|---|
CLOUDFLARE_API_TOKEN |
CloudFlare API token | CDN deployment |
CLOUDFLARE_ZONE_ID |
CloudFlare zone identifier | CDN deployment |
SLACK_WEBHOOK |
Slack webhook URL for notifications | Team notifications |
How to Generate SSH Keys
# On your local machine, generate a key pair
ssh-keygen -t ed25519 -C "github-actions-cv-site" -f ~/.ssh/cv-site-deploy
# Copy the public key to your VM
ssh-copy-id -i ~/.ssh/cv-site-deploy.pub user@your-vm.example.com
# Add the PRIVATE key content to GitHub Secrets
cat ~/.ssh/cv-site-deploy
# Copy the entire output (including -----BEGIN and -----END lines)
Workflow Files Structure
Create these files in your repository:
cv-site/
├── .github/
│ └── workflows/
│ ├── deploy.yml # Main deployment workflow
│ ├── cdn-deploy.yml # CDN optimization (optional)
│ └── test.yml # CI testing workflow
├── scripts/
│ ├── deploy.sh # Deployment script for VM
│ ├── healthcheck.sh # Post-deployment validation
│ └── rollback.sh # Rollback to previous version
├── config/
│ └── systemd/
│ └── cv-site.service # Systemd service file
└── Makefile # Build targets
Main Deployment Workflow
File: .github/workflows/deploy.yml
name: Deploy CV Site to VM
on:
push:
branches:
- main
- production
workflow_dispatch:
inputs:
environment:
description: 'Deployment environment'
required: true
default: 'production'
type: choice
options:
- production
- staging
env:
GO_VERSION: '1.22'
APP_NAME: 'cv-site'
BUILD_DIR: './build'
jobs:
test:
name: Run Tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Download dependencies
run: go mod download
- name: Run tests
run: |
go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage.txt
fail_ci_if_error: false
build:
name: Build Application
runs-on: ubuntu-latest
needs: test
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Build binary
run: |
mkdir -p ${{ env.BUILD_DIR }}
# Build for Linux AMD64 (typical VM architecture)
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags="-w -s -X main.Version=${{ github.sha }} -X main.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-o ${{ env.BUILD_DIR }}/${{ env.APP_NAME }} \
./cmd/${{ env.APP_NAME }}
- name: Compress binary
run: |
cd ${{ env.BUILD_DIR }}
tar -czf ${{ env.APP_NAME }}-${{ github.sha }}.tar.gz ${{ env.APP_NAME }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: cv-site-binary
path: ${{ env.BUILD_DIR }}/${{ env.APP_NAME }}-${{ github.sha }}.tar.gz
retention-days: 30
deploy:
name: Deploy to VM
runs-on: ubuntu-latest
needs: build
environment:
name: ${{ github.event.inputs.environment || 'production' }}
url: https://cv.example.com
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: cv-site-binary
path: ./build
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -p ${{ secrets.SSH_PORT || 22 }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Deploy to VM
env:
SSH_KEY: ~/.ssh/deploy_key
SSH_USER: ${{ secrets.SSH_USER }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_PORT: ${{ secrets.SSH_PORT || 22 }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
run: |
# Extract artifact
cd build
tar -xzf ${{ env.APP_NAME }}-${{ github.sha }}.tar.gz
# Upload binary to VM
scp -i $SSH_KEY -P $SSH_PORT ${{ env.APP_NAME }} \
$SSH_USER@$SSH_HOST:$DEPLOY_PATH/${{ env.APP_NAME }}.new
# Upload deployment script
scp -i $SSH_KEY -P $SSH_PORT ../scripts/deploy.sh \
$SSH_USER@$SSH_HOST:$DEPLOY_PATH/
# Execute deployment on VM
ssh -i $SSH_KEY -p $SSH_PORT $SSH_USER@$SSH_HOST << 'ENDSSH'
cd ${{ secrets.DEPLOY_PATH }}
# Make scripts executable
chmod +x deploy.sh
chmod +x ${{ env.APP_NAME }}.new
# Run deployment script
./deploy.sh ${{ env.APP_NAME }}
ENDSSH
- name: Health check
run: |
echo "Waiting for application to start..."
sleep 10
# Check if service is running
ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT || 22 }} \
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
"systemctl is-active ${{ env.APP_NAME }}"
# HTTP health check
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" https://cv.example.com/health)
if [ "$RESPONSE" = "200" ]; then
echo "✅ Health check passed (HTTP $RESPONSE)"
else
echo "❌ Health check failed (HTTP $RESPONSE)"
exit 1
fi
- name: Send notification
if: always()
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
run: |
STATUS="${{ job.status }}"
COLOR="good"
if [ "$STATUS" != "success" ]; then
COLOR="danger"
fi
curl -X POST "$SLACK_WEBHOOK" \
-H "Content-Type: application/json" \
-d "{
\"attachments\": [{
\"color\": \"$COLOR\",
\"title\": \"CV Site Deployment $STATUS\",
\"text\": \"Deployment to VM completed\",
\"fields\": [
{\"title\": \"Branch\", \"value\": \"${{ github.ref_name }}\", \"short\": true},
{\"title\": \"Commit\", \"value\": \"${{ github.sha }}\", \"short\": true},
{\"title\": \"Environment\", \"value\": \"${{ github.event.inputs.environment || 'production' }}\", \"short\": true}
]
}]
}" || true
- name: Cleanup SSH keys
if: always()
run: |
rm -f ~/.ssh/deploy_key
CDN Integration (Optional)
File: .github/workflows/cdn-deploy.yml
name: CloudFlare CDN Deployment
on:
push:
branches:
- main
paths:
- 'static/**'
- 'assets/**'
workflow_dispatch:
inputs:
purge_cache:
description: 'Purge CDN cache'
required: false
default: 'true'
type: choice
options:
- 'true'
- 'false'
jobs:
deploy-cdn:
name: Deploy Static Assets to CDN
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -p ${{ secrets.SSH_PORT || 22 }} ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Sync static assets to VM
run: |
rsync -avz -e "ssh -i ~/.ssh/deploy_key -p ${{ secrets.SSH_PORT || 22 }}" \
--delete \
./static/ \
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ secrets.DEPLOY_PATH }}/static/
- name: Configure CloudFlare
if: secrets.CLOUDFLARE_API_TOKEN != ''
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }}
run: |
# Enable WebP
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/${CLOUDFLARE_ZONE_ID}/settings/webp" \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
-H "Content-Type: application/json" \
--data '{"value":"on"}'
# Enable Brotli compression
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/${CLOUDFLARE_ZONE_ID}/settings/brotli" \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
-H "Content-Type: application/json" \
--data '{"value":"on"}'
- name: Purge CDN cache
if: github.event.inputs.purge_cache == 'true' || github.event_name == 'push'
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }}
run: |
curl -X POST "https://api.cloudflare.com/client/v4/zones/${CLOUDFLARE_ZONE_ID}/purge_cache" \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
-H "Content-Type: application/json" \
--data '{"purge_everything":true}'
- name: Cleanup
if: always()
run: rm -f ~/.ssh/deploy_key
Build Artifacts
What Gets Built
For a Go application, the main artifact is the compiled binary:
- Binary:
cv-site(orcv-site.exefor Windows) - Archive:
cv-site-{commit-sha}.tar.gz - Metadata: Version info embedded during build
Build Flags Explained
CGO_ENABLED=0 # Static binary (no C dependencies)
GOOS=linux # Target OS
GOARCH=amd64 # Target architecture
-ldflags="-w -s # Strip debug info (smaller binary)
-X main.Version=$SHA # Embed git commit
-X main.BuildTime=$DATE" # Embed build timestamp
Artifact Storage
- GitHub Actions Artifacts: 30 days retention
- VM Server:
/opt/cv-site/releases/{version}/ - Backup: Previous 5 versions kept for rollback
Deployment Scripts
File: scripts/deploy.sh
#!/bin/bash
set -e
APP_NAME="${1:-cv-site}"
DEPLOY_PATH="${DEPLOY_PATH:-/opt/cv-site}"
SERVICE_NAME="cv-site"
echo "🚀 Starting deployment of $APP_NAME"
# Create backup of current version
if [ -f "$DEPLOY_PATH/$APP_NAME" ]; then
echo "📦 Backing up current version..."
cp "$DEPLOY_PATH/$APP_NAME" "$DEPLOY_PATH/$APP_NAME.backup"
fi
# Move new binary into place
echo "📥 Installing new version..."
mv "$DEPLOY_PATH/$APP_NAME.new" "$DEPLOY_PATH/$APP_NAME"
chmod +x "$DEPLOY_PATH/$APP_NAME"
# Restart service
echo "🔄 Restarting service..."
sudo systemctl restart "$SERVICE_NAME"
# Wait for service to start
sleep 3
# Check service status
if sudo systemctl is-active --quiet "$SERVICE_NAME"; then
echo "✅ Service started successfully"
# Remove backup after successful deployment
rm -f "$DEPLOY_PATH/$APP_NAME.backup"
else
echo "❌ Service failed to start - rolling back"
# Rollback to backup
if [ -f "$DEPLOY_PATH/$APP_NAME.backup" ]; then
mv "$DEPLOY_PATH/$APP_NAME.backup" "$DEPLOY_PATH/$APP_NAME"
sudo systemctl restart "$SERVICE_NAME"
echo "⚠️ Rolled back to previous version"
fi
exit 1
fi
echo "🎉 Deployment completed successfully"
File: scripts/healthcheck.sh
#!/bin/bash
set -e
HEALTH_URL="${HEALTH_URL:-http://localhost:8080/health}"
MAX_RETRIES=30
RETRY_DELAY=2
echo "🏥 Running health check..."
for i in $(seq 1 $MAX_RETRIES); do
if curl -sf "$HEALTH_URL" > /dev/null; then
echo "✅ Health check passed (attempt $i)"
exit 0
fi
echo "⏳ Waiting for service... (attempt $i/$MAX_RETRIES)"
sleep $RETRY_DELAY
done
echo "❌ Health check failed after $MAX_RETRIES attempts"
exit 1
Environment Configuration
Systemd Service File
Create: config/systemd/cv-site.service
[Unit]
Description=CV Site Go Application
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/cv-site
ExecStart=/opt/cv-site/cv-site
Restart=always
RestartSec=5s
# Environment variables
Environment="PORT=8080"
Environment="GIN_MODE=release"
EnvironmentFile=/opt/cv-site/.env
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/cv-site/data
# Resource limits
LimitNOFILE=65536
MemoryMax=512M
[Install]
WantedBy=multi-user.target
Installation on VM
# Copy service file
sudo cp config/systemd/cv-site.service /etc/systemd/system/
# Reload systemd
sudo systemctl daemon-reload
# Enable service
sudo systemctl enable cv-site
# Start service
sudo systemctl start cv-site
# Check status
sudo systemctl status cv-site
Testing Strategy
File: .github/workflows/test.yml
name: Test CV Site
on:
pull_request:
branches: [main, develop]
push:
branches: [main, develop]
jobs:
test:
name: Test on Go ${{ matrix.go-version }}
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.21', '1.22']
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: true
- name: Install dependencies
run: go mod download
- name: Run linter
uses: golangci/golangci-lint-action@v3
with:
version: latest
- name: Run tests
run: |
go test -v -race -coverprofile=coverage.txt ./...
- name: Build
run: |
go build -v ./...
Makefile
Create a Makefile for local development and CI consistency:
.PHONY: build test deploy clean help
APP_NAME := cv-site
BUILD_DIR := ./build
GO_VERSION := 1.22
VERSION := $(shell git describe --tags --always --dirty)
BUILD_TIME := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -ldflags="-w -s -X main.Version=$(VERSION) -X main.BuildTime=$(BUILD_TIME)"
## help: Display this help message
help:
@echo "Available targets:"
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
## build: Build the application binary
build:
@echo "🔨 Building $(APP_NAME)..."
@mkdir -p $(BUILD_DIR)
CGO_ENABLED=0 go build $(LDFLAGS) -o $(BUILD_DIR)/$(APP_NAME) ./cmd/$(APP_NAME)
@echo "✅ Build complete: $(BUILD_DIR)/$(APP_NAME)"
## test: Run all tests
test:
@echo "🧪 Running tests..."
go test -v -race -coverprofile=coverage.txt ./...
## lint: Run linter
lint:
@echo "🔍 Running linter..."
golangci-lint run
## clean: Clean build artifacts
clean:
@echo "🧹 Cleaning..."
rm -rf $(BUILD_DIR)
go clean
## run: Run the application locally
run: build
@echo "🚀 Starting $(APP_NAME)..."
$(BUILD_DIR)/$(APP_NAME)
## deploy: Build and deploy (for CI use)
deploy: build
@echo "📦 Deploying..."
# Deployment handled by GitHub Actions
Deployment Checklist
Pre-Deployment
-
GitHub Secrets configured
SSH_PRIVATE_KEYaddedSSH_HOSTsetSSH_USERsetDEPLOY_PATHconfigured
-
VM Server prepared
- SSH access configured
- Deploy user created with sudo privileges
- Application directory created (
/opt/cv-site) - Systemd service installed
- Firewall rules configured (port 8080)
-
Code repository ready
- Workflow files in
.github/workflows/ - Deployment scripts in
scripts/ - Systemd service file in
config/systemd/ - Tests passing locally
- Workflow files in
First Deployment
- Push to GitHub:
git push origin main - Monitor Actions: Go to
Actionstab in GitHub - Check logs: Verify each step completes
- Test deployment: Visit your site URL
- Verify service: SSH to VM and run
systemctl status cv-site
Post-Deployment
- Health check passes
- Service running:
systemctl is-active cv-site - Logs clean:
journalctl -u cv-site -n 50 - Backup created: Previous version backed up
- Rollback tested: Verify rollback script works
Troubleshooting
Common Issues
1. SSH Connection Failed
# Test SSH connection manually
ssh -i ~/.ssh/cv-site-deploy user@your-vm.example.com
# Check SSH key format
head -n 1 ~/.ssh/cv-site-deploy
# Should show: -----BEGIN OPENSSH PRIVATE KEY-----
2. Binary Won't Execute
# Check binary architecture
file /opt/cv-site/cv-site
# Should show: ELF 64-bit LSB executable, x86-64
# Check permissions
ls -la /opt/cv-site/cv-site
chmod +x /opt/cv-site/cv-site
3. Service Fails to Start
# Check service status
sudo systemctl status cv-site
# View logs
sudo journalctl -u cv-site -n 100 --no-pager
# Test binary manually
sudo -u www-data /opt/cv-site/cv-site
4. Health Check Timeout
# Test health endpoint locally on VM
curl http://localhost:8080/health
# Check if port is listening
sudo netstat -tlnp | grep 8080
# Check firewall
sudo ufw status
Advanced Features
Blue-Green Deployment
Modify deploy.sh to support zero-downtime deployments:
#!/bin/bash
# Blue-Green deployment strategy
BLUE_PORT=8080
GREEN_PORT=8081
CURRENT_PORT=$(cat /opt/cv-site/current_port)
NEW_PORT=$([[ $CURRENT_PORT == $BLUE_PORT ]] && echo $GREEN_PORT || echo $BLUE_PORT)
# Start new version on alternate port
PORT=$NEW_PORT /opt/cv-site/cv-site.new &
# Wait and health check
sleep 5
curl -f http://localhost:$NEW_PORT/health || exit 1
# Switch nginx upstream
sudo sed -i "s/localhost:$CURRENT_PORT/localhost:$NEW_PORT/" /etc/nginx/sites-enabled/cv-site
sudo systemctl reload nginx
# Stop old version
pkill -f "cv-site.*$CURRENT_PORT"
# Update current port
echo $NEW_PORT > /opt/cv-site/current_port
Rollback Strategy
#!/bin/bash
# scripts/rollback.sh
DEPLOY_PATH="/opt/cv-site"
BACKUP_PATH="$DEPLOY_PATH/releases"
# List available versions
echo "Available versions:"
ls -1t $BACKUP_PATH | head -5
# Rollback to previous version
PREVIOUS=$(ls -1t $BACKUP_PATH | head -1)
cp "$BACKUP_PATH/$PREVIOUS/cv-site" "$DEPLOY_PATH/cv-site"
sudo systemctl restart cv-site
echo "Rolled back to: $PREVIOUS"
Performance Optimization
Binary Size Reduction
# Use UPX compression (optional)
upx --best --lzma build/cv-site
# Result: ~70% size reduction
# Before: 15MB → After: 4.5MB
Caching Strategy
Add to workflow for faster builds:
- name: Cache Go modules
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
Security Best Practices
-
SSH Key Security
- Use Ed25519 keys (stronger than RSA)
- Never commit private keys
- Rotate keys every 90 days
-
Service Hardening
- Run as non-root user (
www-data) - Use systemd security features
- Limit file system access
- Run as non-root user (
-
Secret Management
- Use GitHub Encrypted Secrets
- Never log sensitive data
- Use environment files on VM
-
Network Security
- Restrict SSH to GitHub Actions IPs (if possible)
- Use firewall rules
- Enable fail2ban
Monitoring & Logging
Add Logging to Deployment
- name: Log deployment
run: |
echo "Deployment started at $(date)" >> /var/log/cv-site/deploy.log
echo "Commit: ${{ github.sha }}" >> /var/log/cv-site/deploy.log
echo "Branch: ${{ github.ref_name }}" >> /var/log/cv-site/deploy.log
Application Monitoring
// Add to your Go app for health checks
func healthHandler(c *gin.Context) {
c.JSON(200, gin.H{
"status": "healthy",
"version": Version,
"uptime": time.Since(startTime).String(),
})
}
Summary
Key Differences from La Porra
| Aspect | La Porra (Node/Bun) | CV Site (Go) |
|---|---|---|
| Runtime | Node.js/Bun | Native binary |
| Build | bun run build |
go build |
| Artifact | /dist directory | Single binary |
| Dependencies | node_modules | Statically linked |
| Deployment | File sync | Binary upload |
| Service | PM2/systemd | systemd |
Deployment Flow
┌─────────────┐
│ Push to Git │
└──────┬──────┘
│
v
┌─────────────────┐
│ GitHub Actions │
│ - Test │
│ - Build Binary │
│ - Create Artifact│
└──────┬──────────┘
│
v
┌─────────────────┐
│ Upload to VM │
│ via SSH/SCP │
└──────┬──────────┘
│
v
┌─────────────────┐
│ Execute deploy.sh│
│ - Backup old │
│ - Install new │
│ - Restart service│
└──────┬──────────┘
│
v
┌─────────────────┐
│ Health Check │
│ - HTTP test │
│ - Service status│
└──────┬──────────┘
│
v
┌─────────────────┐
│ Send Notification│
└─────────────────┘
Quick Start Commands
# 1. Clone repository
git clone https://github.com/juanatsap/cv-site.git
cd cv-site
# 2. Create workflow files
mkdir -p .github/workflows
# Copy workflow YAML files from this guide
# 3. Create deployment scripts
mkdir -p scripts config/systemd
# Copy scripts from this guide
# 4. Add secrets to GitHub
# Go to Settings → Secrets and variables → Actions
# Add all required secrets
# 5. Test locally
make test
make build
# 6. Deploy
git add .
git commit -m "Add GitHub Actions deployment"
git push origin main
Additional Resources
- GitHub Actions Documentation: https://docs.github.com/en/actions
- Go Build Documentation: https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies
- Systemd Service Files: https://www.freedesktop.org/software/systemd/man/systemd.service.html
- SSH Key Management: https://docs.github.com/en/authentication/connecting-to-github-with-ssh
Last Updated: January 2025 Maintained By: Development Team Support: Create an issue in the repository