DEV Community

Cover image for # Automating Python Deployments to a VPS with GitHub Actions
Ernest Kabahima
Ernest Kabahima

Posted on

# Automating Python Deployments to a VPS with GitHub Actions

If you are learning deployment for the first time, the best path is to start simple: run your Python app on a VPS, keep it alive with systemd, put Nginx in front of it, and only then automate the whole process with GitHub Actions. This two-part approach makes CI/CD much easier to understand because you first learn how deployment works by hand, then you learn how to automate it. onehost

Introduction

Deployment is the process of moving your application from development into a live environment where other people can access it. For a beginner, that usually means a VPS, a reverse proxy like Nginx, and a process manager such as systemd to keep the app running reliably. onehost

This article is split into two parts:

  • Part 1: Set up the VPS, run the Python app, configure Nginx, and keep the system live.
  • Part 2: Add GitHub Actions to automate testing and deployment.

Part 1: VPS and Nginx Lab

The goal in Part 1 is to get a working production-style setup without automation first. Once you understand this manual setup, CI/CD in Part 2 will make a lot more sense.

1. Choose your Python app

Start with a simple Python web app using Flask, FastAPI, or Django. Keep the app small so you can focus on deployment rather than application complexity, and make sure it has a health endpoint such as /health so you can test whether it is alive after deployment.

A minimal app should:

  • respond to web requests,
  • read environment variables,
  • have clearly defined dependencies,
  • expose a health check route.

2. Prepare the VPS

Use an Ubuntu VPS for the simplest beginner-friendly setup. Connect with SSH, install Python and Git, and create a dedicated user for deployment rather than using the root account.

A basic VPS setup usually includes:

  • installing Python,
  • installing git,
  • creating a virtual environment,
  • opening only the ports you need,
  • configuring SSH access securely.

3. Keep the app live with systemd

If you run python app.py manually in a terminal, the app stops when you disconnect or reboot the server. systemd fixes this by running the app as a service, starting it automatically on boot, and restarting it if it crashes. onehost

A typical systemd service gives you:

  • automatic start on boot,
  • automatic restart on failure,
  • centralized logs,
  • easier service management with systemctl.

This is one of the most important beginner deployment lessons because it turns a fragile script into a real service.

4. Put Nginx in front

Nginx acts as a reverse proxy: it receives traffic from the internet and forwards requests to your Python app running on localhost. This is the standard way to expose a web app on a VPS because it keeps the app private while Nginx handles public traffic on ports 80 and 443. space-node

Why use Nginx?

  • It handles domain routing.
  • It can terminate HTTPS.
  • It can proxy traffic cleanly to your app.
  • It keeps your Python app off the public internet.

In practice, your app listens on something like 127.0.0.1:8000, and Nginx listens on your public domain or IP address.

5. Test the manual setup

Before moving to automation, make sure the manual setup is stable.

Check that:

  • the app starts correctly,
  • the app survives a restart,
  • Nginx routes requests properly,
  • the health endpoint works,
  • logs are readable through journalctl or your app logs.

At this point, you have a real production-style deployment, even though it is not automated yet.


Part 2: CI/CD Lab

Now that the app is running manually, you can automate the process with GitHub Actions. The goal here is to make every push to GitHub test the app and then deploy it to the VPS safely. advantch

1. Understand GitHub Actions

GitHub Actions is GitHub’s automation system. It runs workflows on events such as pushes, pull requests, or manual triggers, and those workflows can install dependencies, run tests, and deploy code.

A workflow usually has:

  • a trigger,
  • one or more jobs,
  • steps inside each job.

2. Add build and test steps

Start automation with testing, not deployment. Your workflow should install Python dependencies and run tests so bad code never reaches the server.

Typical CI steps:

  • checkout the repository,
  • set up Python,
  • install dependencies,
  • run unit tests,
  • run lint checks if you have them.

If tests fail, deployment should stop immediately.

3. Deploy to the VPS

Once testing passes, GitHub Actions can connect to your VPS over SSH and deploy the new code. The workflow can either pull the latest commit on the server or send a build artifact, depending on how your app is structured.

A simple deployment flow looks like this:

  1. Push code to main.
  2. GitHub Actions runs tests.
  3. If tests pass, it SSHs into the VPS.
  4. The server updates the code.
  5. systemd restarts the app.
  6. Nginx continues serving traffic.

This pattern is easy to understand and works well for small to medium Python apps.

4. Store secrets safely

Never hardcode passwords or private keys in your repository. Use GitHub Secrets for SSH keys, server addresses, and other sensitive values. This keeps your pipeline secure and prevents credentials from leaking into source control.

Good secret management means:

  • no private keys in Git,
  • no passwords in code,
  • minimal access on the VPS,
  • clear separation between app config and source code.

5. Keep the system live during deploys

A good deployment does not just copy files; it keeps the service available as much as possible. systemd helps by restarting the app after an update, and Nginx keeps the public side stable while the backend is refreshed.

For beginners, the simplest practical target is:

  • short downtime or near-zero downtime,
  • a fast restart,
  • a health check after deployment,
  • logs ready for troubleshooting.

6. Add production safety

Once deployment works, make it safer.

Add:

  • rollback steps,
  • health checks,
  • deployment logs,
  • branch protection,
  • staging before production if possible.

The goal is not just “it deploys,” but “it deploys reliably.”


Crossroads: Docker, Terraform, and Kubernetes

After you understand the VPS workflow, you reach a crossroads where you decide whether to stay simple or move into more advanced deployment tooling. This is where Docker, Terraform, and Kubernetes become relevant. developer.hashicorp

Docker

Docker packages your app and dependencies into a container, making the runtime more consistent across machines. This helps reduce environment drift and makes the app easier to move between local development, testing, and production.

Use Docker when:

  • environment consistency matters,
  • you want portable builds,
  • your app depends on multiple services.

Terraform

Terraform lets you define infrastructure as code, so you can provision and manage infrastructure with configuration files instead of clicking through a cloud console. It is useful when you want your VPS, networking, and cloud resources to be reproducible and version-controlled. developer.hashicorp

Use Terraform when:

  • infrastructure changes often,
  • you want repeatable cloud provisioning,
  • your team needs auditable infrastructure changes.

Kubernetes

Kubernetes is an orchestration platform for running containerized apps at scale. It is powerful, but it also adds a lot of complexity, so it is usually not the best starting point for a beginner with a single Python app and one VPS. docs.docker

Use Kubernetes when:

  • you have multiple services,
  • you need auto-scaling or advanced orchestration,
  • you are ready for the operational overhead.

Other tools

Other useful tools include:

  • Docker Compose for multi-container apps on one server,
  • Ansible for server configuration,
  • cloud-init for server bootstrap automation,
  • managed cloud platforms when you want less server maintenance.

Choosing the right path

For most beginners, the best path is:

  1. Build the Python app.
  2. Deploy it to a VPS.
  3. Run it with systemd.
  4. Put Nginx in front.
  5. Add GitHub Actions for CI/CD.
  6. Only then explore Docker, Terraform, or Kubernetes.

This order works because each step builds on the one before it. You learn the fundamentals first, then you add tooling only when you have a real need.


Conclusion

The simplest reliable deployment system is often the best one to start with. For a beginner, Python + VPS + systemd + Nginx gives you the foundation, and GitHub Actions adds automation once you understand the manual process.

Top comments (0)