· 3 min read
Automating Flask App Deployment with GitHub Actions and Jisho App
Last time I created the jisho microservice. In this guide, I’ll walk through how to automatically build and deploy it using GitHub Actions, covering two scenarios:
- Demo deployment using a GitHub self-hosted runner
- Production deployment via SSH to an external server
Whether you’re testing locally or pushing to a live environment, GitHub Actions can make your CI/CD seamless and reliable.
While you are reading this article, the jisho service is online in https://jisho.crazyhungry.party/
How I hosted it in my domain will be in another blog (or probably too simple to post it :D )
All code in this article are here.
🧩 Project Overview
I added the following Dockerfile to the repo so that GH action can build the repo.
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"]This app can be run as a container listening on port 5000.
🧪 Method 1: Deploy to a GitHub Self-Hosted Runner (for Demos)
This method is perfect if:
- You want to test auto-deployment without exposing a production environment.
- Your VM has no public IP (i.e., runs behind NAT or a private network).
- You can install the GitHub Actions runner directly on the machine
🧱 Steps:
Install GitHub Actions Runner on your demo machine
# From your GitHub repo settings > Actions > Runners # Follow the setup instructions to install and register the runner
(basically the command line is pretty detailed from Github when you try to create the runner so I will skip it here).
- Use this GitHub Actions workflow:
# .github/workflows/deploy.yml
name: Demo Deploy via Self-Hosted Runner
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: self-hosted
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t jisho-app:latest .
- name: Stop and remove old container
run: |
docker stop jisho-app || true
docker rm jisho-app || true
- name: Run container
run: |
docker run -d \
--name jisho-app \
-p 80:5000 \
jisho-app:latestMake sure port 80 is exposed and not blocked by firewall. You can change it to whatever you want.
🔐 Method 2: Deploy via SSH to a Remote Production Server
For production, it’s best to keep GitHub and your app server decoupled, and deploy using SSH and scp.
🧱 Prerequisites
- Your production server has a public IP or is reachable via DNS.
- You’ve created an SSH key pair and added the public key to
~/.ssh/authorized_keyson the server. - The private key is stored in your GitHub repo as a secret (
SSH_KEY). - You allow connections on port 22 or your configured SSH port.
🗂 GitHub Secrets
| Name | Value |
|---|---|
SSH_HOST | e.g. yourserver.com |
SSH_USER | e.g. deployer |
SSH_KEY | Private key string |
🚀 Example Workflow
name: Production Deploy via SSH
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t jisho-app:latest .
- name: Save Docker image as tarball
run: docker save jisho-app:latest -o jisho-app.tar
- name: Copy Docker image to remote server
uses: appleboy/scp-action@v0.1.4
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
source: "jisho-app.tar"
target: "~/"
- name: Deploy on remote server
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
script: |
docker load -i ~/jisho-app.tar
docker stop jisho-app || true
docker rm jisho-app || true
docker run -d --name jisho-app -p 80:5000 jisho-app:latest📝 Summary
| Scenario | Method | Pros | Use When… |
|---|---|---|---|
| Demo | Self-hosted runner | No SSH needed, internal-only, fast builds | Testing local VMs, behind NAT |
| Production | SSH + SCP from GitHub Actions | Secure, clean separation of build and deploy | Public server or cloud production setup |
🔒 Security Best Practices
- Use SSH key authentication (no passwords).
- Restrict server access to GitHub IP ranges if possible.
- Rotate your deployment keys periodically.