· 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:

  1. Demo deployment using a GitHub self-hosted runner
  2. 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:

  1. 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).

  1. 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:latest

Make 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_keys on 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

NameValue
SSH_HOSTe.g. yourserver.com
SSH_USERe.g. deployer
SSH_KEYPrivate 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/[email protected]
        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/[email protected]
        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

ScenarioMethodProsUse When…
DemoSelf-hosted runnerNo SSH needed, internal-only, fast buildsTesting local VMs, behind NAT
ProductionSSH + SCP from GitHub ActionsSecure, clean separation of build and deployPublic 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.
Back to Blog