Skip to content

Deploy to On-Premise Server #16

Deploy to On-Premise Server

Deploy to On-Premise Server #16

Workflow file for this run

name: Deploy to On-Premise Server
on:
workflow_dispatch:
inputs:
branch:
description: 'Branch to deploy'
required: true
type: choice
options:
- main
- dev
- staging
environment:
description: 'Deployment environment'
required: true
default: 'production'
type: string
env:
REGISTRY: ghcr.io
IMAGE_NAME: purrowallet/purro-core
jobs:
build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ inputs.branch }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=${{ inputs.branch }}-latest
type=raw,value=${{ inputs.branch }}-${{ github.run_number }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
build-args: |
BUILD_DATE=${{ github.event.head_commit.timestamp }}
VCS_REF=${{ github.sha }}
VERSION=${{ inputs.branch }}-${{ github.run_number }}
deploy:
name: Deploy to Server
runs-on: ubuntu-latest
needs: build-and-push
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ inputs.branch }}
- name: Connect to Tailscale
uses: tailscale/github-action@v2
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:ci
- name: Setup SSH
run: |
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "=== Debug: SSH Key Info ==="
echo "Key length: $(echo '${{ secrets.SSH_PRIVATE_KEY }}' | wc -c) characters"
echo "Key lines: $(echo '${{ secrets.SSH_PRIVATE_KEY }}' | wc -l) lines"
echo "First 50 chars: $(echo '${{ secrets.SSH_PRIVATE_KEY }}' | head -c 50)"
# Use printf to preserve newlines properly
printf '%s\n' "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
# Verify file was written
if [ ! -s ~/.ssh/id_rsa ]; then
echo "ERROR: SSH key file is empty!"
exit 1
fi
echo "=== SSH key file created ==="
echo "File size: $(wc -c < ~/.ssh/id_rsa) bytes"
echo "File lines: $(wc -l < ~/.ssh/id_rsa) lines"
chmod 600 ~/.ssh/id_rsa
# Validate SSH key format
echo "=== Validating SSH key format ==="
if ssh-keygen -y -f ~/.ssh/id_rsa > /dev/null 2>&1; then
echo "✅ SSH key format is VALID"
else
echo "❌ SSH key format is INVALID!"
echo "Key content (first 2 lines):"
head -2 ~/.ssh/id_rsa
exit 1
fi
# Add server to known_hosts
echo "=== Adding server to known_hosts ==="
echo "Server host: ${{ secrets.SERVER_HOST }}"
if ssh-keyscan -H -T 10 ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts 2>&1; then
echo "✅ ssh-keyscan successful"
else
echo "⚠️ ssh-keyscan failed, but continuing..."
echo "This might be ok if server uses non-standard SSH config"
fi
echo "✅ SSH setup completed successfully"
- name: Copy docker-compose.yml to server
run: |
echo "=== Copying docker-compose.yml to server ==="
scp -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
docker-compose.yml ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:${{ secrets.RUNTIME_PATH }}/
echo "✅ File copied successfully"
- name: Deploy on server
run: |
echo "=== Deploying to server ==="
# Pass environment variables to SSH session
ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} \
"GH_TOKEN='${{ secrets.GHCR_PAT }}' \
REGISTRY='${{ env.REGISTRY }}' \
IMAGE='${{ env.IMAGE_NAME }}' \
BRANCH='${{ inputs.branch }}' \
GITHUB_USER='${{ github.actor }}' \
CONFIG_PATH='${{ secrets.CONFIG_PATH }}' \
RUNTIME_PATH='${{ secrets.RUNTIME_PATH }}' \
bash -s" << 'ENDSSH'
# Navigate to runtime directory
cd ${RUNTIME_PATH}
# Login to GitHub Container Registry with PAT
echo "${GH_TOKEN}" | docker login ${REGISTRY} -u ${GITHUB_USER} --password-stdin
# Set image name and env file path for docker-compose
export DOCKER_IMAGE="${REGISTRY}/${IMAGE}:${BRANCH}-latest"
export ENV_FILE="${CONFIG_PATH}/.env"
# Pull latest image
docker pull ${DOCKER_IMAGE}
# Stop and remove old container
docker-compose down
# Start new container with pulled image and custom env file
docker-compose up -d
# Clean up old images
docker image prune -af --filter "until=72h"
ENDSSH
- name: Cleanup
if: always()
run: |
rm -f ~/.ssh/id_rsa