Github
installation
cli
usage
gh repo
create interactively
gh repo create
github pages
uses jekyll
setup
-
Settings>Pages
- “Deploy from a branch” main
- Click the Save button.
-
create ”./_config.yml”
example
theme: minima
title: dev notes
author: elliot reed
description: notes
site
-
create ”./index.md” or ”./README.md”
- add homepage content
-
jekyll, create blog with files named “_posts/YYYY-MM-DD-title.md”
-
include title and date
--- title: "YOUR-TITLE" date: YYYY-MM-DD ---
Actions for VPS
1. Generate Deploy SSH Key on VPS
ssh-keygen -t ed25519 -C "github-actions-vps-deploy" -f ~/.ssh/github_vps_deploy
cat ~/.ssh/github_vps_deploy.pub >> ~/.ssh/authorized_keys
cat ~/.ssh/github_vps_deploy
Copy the private key output.
2. Add Secrets to GitHub Repository
Settings → Secrets and variables → Actions → New repository secret
Add three secrets:
VPS_SSH_KEY- The private key from aboveVPS_HOST- Your VPS IP addressVPS_USER- Your VPS username
3. Create Workflow File
Create .github/workflows/deploy.yml in your repository.
For Node.js Apps:
name: Deploy to VPS
on:
push:
branches: [ main ]
workflow_dispatch:
env:
VPS_HOST: ${{ secrets.VPS_HOST }}
VPS_USER: ${{ secrets.VPS_USER }}
APP_NAME: your-app-name
PROCESS_NAME: your-process-name
NODE_VERSION: "24"
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Set remote path
run: echo "REMOTE_APP_PATH=~/apps/${{ env.APP_NAME }}" >> $GITHUB_ENV
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Setup SSH key
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.VPS_SSH_KEY }}
- name: Add SSH host to known_hosts
run: ssh-keyscan ${{ env.VPS_HOST }} >> ~/.ssh/known_hosts
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Deploy via rsync
run: |
rsync -avz --delete \
--exclude 'node_modules' \
--exclude '.git' \
--exclude '.github' \
--exclude '.env*' \
--exclude '*.log' \
./dist/ package.json package-lock.json \
${{ env.VPS_USER }}@${{ env.VPS_HOST }}:${{ env.REMOTE_APP_PATH }}/
- name: Install dependencies and restart
run: |
ssh ${{ env.VPS_USER }}@${{ env.VPS_HOST }} << 'ENDSSH'
cd ${{ env.REMOTE_APP_PATH }}
npm ci --omit=dev
pm2 delete ${{ env.PROCESS_NAME }} || true
NODE_ENV=production pm2 start main.js --name ${{ env.PROCESS_NAME }}
pm2 save
ENDSSH
- name: Deployment summary
run: |
echo "🚀 Deployed to ${{ env.VPS_HOST }}"
echo "📁 App: ${{ env.APP_NAME }}"
For Static Sites:
name: Deploy Static Site to VPS
on:
push:
branches: [ main ]
workflow_dispatch:
env:
VPS_HOST: ${{ secrets.VPS_HOST }}
VPS_USER: ${{ secrets.VPS_USER }}
SITE_NAME: your-site-name
NODE_VERSION: "24"
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Set remote path
run: echo "REMOTE_SITE_PATH=~/apps/${{ env.SITE_NAME }}" >> $GITHUB_ENV
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Setup SSH key
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.VPS_SSH_KEY }}
- name: Add SSH host to known_hosts
run: ssh-keyscan ${{ env.VPS_HOST }} >> ~/.ssh/known_hosts
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Deploy via rsync
run: |
rsync -avz --delete \
--exclude 'node_modules' \
--exclude '.git' \
--exclude '.github' \
--exclude 'src' \
./dist/ \
${{ env.VPS_USER }}@${{ env.VPS_HOST }}:${{ env.REMOTE_SITE_PATH }}/
- name: Deployment summary
run: |
echo "🚀 Deployed to ${{ env.VPS_HOST }}"
echo "📁 Site: ${{ env.SITE_NAME }}"
4. Customize Variables
Update these in the workflow file:
APP_NAME/SITE_NAME- Your project directory namePROCESS_NAME- PM2 process name (Node apps only)NODE_VERSION- Node.js version to use for build
5. Deploy
Push to main branch or manually trigger from GitHub Actions tab.
Notes
- Workflows run on every push to main branch
workflow_dispatchallows manual triggering from GitHub UI- Node apps use PM2 for process management
- Static sites just sync files, no runtime process needed
Actions
Automating React App Deployment to Shared Hosting with GitHub Actions
Overview
This document outlines the steps to automate the deployment of a React app from GitHub to shared hosting using rsync over SSH.
1️⃣ Set Up SSH Access
- Generated an SSH key for GitHub Actions:
ssh-keygen -t rsa -b 4096 -f ~/.ssh/github-actions-key -N "" - Added the public key (
~/.ssh/github-actions-key.pub) to the hosting server under~/.ssh/authorized_keysvia cPanel SSH Key Manager (preferred method).
To verify the added keys, run:
ssh-add -l
To display the key values in the console, run:
Public key (on the host)
cat ~/.ssh/github-actions-key.pub
Private key for Github
cat ~/.ssh/github-actions-key
- Configured SSH access:
- Verified SSH connection using:
ssh -p {port and login} - Tested
scpfor manual deployment, butrsyncwas not available locally.
- Verified SSH connection using:
2️⃣ Configured GitHub Actions Workflow
-
Created the workflow file:
mkdir -p .github/workflows nano .github/workflows/deploy.yml -
Added the following YAML configuration:
name: Deploy to Shared Hosting on: push: branches: - main # Runs when pushing to main branch jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v4 - name: Setup SSH key for deployment uses: webfactory/ssh-agent@v0.5.3 with: ssh-private-key: ${{ secrets.DEPLOY_SSH_KEY }} - name: Install dependencies run: npm install - name: Build project run: npm run build - name: Test SSH connectivity run: ssh -o StrictHostKeyChecking=no -p {port} {identifier} "echo 'SSH connection successful'" - name: Ensure target directory exists run: ssh -p {port} {identifier} "mkdir -p {path}" - name: Deploy via rsync run: rsync -avz --delete --exclude '.well-known' --exclude 'cgi-bin' -e "ssh -p {port}" ./public/ {identifier}:{path}—delete will remove files and folders
—exclude to ensure not deleted, check for all files that should stay (.htaccess, .env)
-p port port number for hostings port
./public/ - the folder containing the contents to be transfered (could be “dist” or “build)
identifier (hosting login identifier, accountname#root site)
path (eg: /home/elliotre/site folder)
-
Saved the file and committed it:
git add .github/workflows/deploy.yml git commit -m "Add GitHub Actions deployment workflow" git push origin main
3️⃣ Added SSH Key to GitHub Secrets
- Went to GitHub → Repository → Settings → Secrets and variables → Actions.
- Created a new secret
DEPLOY_SSH_KEY. - Pasted the private SSH key
~/.ssh/github-actions-key
4️⃣ Testing the Deployment
- Made a small change in the React app.
- Committed and pushed:
git add . git commit -m "Test rsync auto-deploy" git push origin main - GitHub Actions built and deployed the app successfully! 🎉
🎯 Final Outcome
✅ Automatic deployment to shared hosting on every push to main
✅ Uses rsync to only update modified files
✅ Deletes old files to keep the deployment clean (optional: remove --delete to disable)
✅ No need for manual file uploads—GitHub handles everything! 🚀
Learning Lab Notes