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
journalctlor 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:
- Push code to
main. - GitHub Actions runs tests.
- If tests pass, it SSHs into the VPS.
- The server updates the code.
-
systemdrestarts the app. - 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:
- Build the Python app.
- Deploy it to a VPS.
- Run it with
systemd. - Put Nginx in front.
- Add GitHub Actions for CI/CD.
- 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)