← Back to blog

The Right Way to Deploy Private GitHub Repos to Your VPS

The Right Way to Deploy Private GitHub Repos to Your VPS

Part 2 of my VPS Deployment Series — If you haven't secured your firewall yet, check out Part 1: Don’t Lock Yourself Out – Enabling UFW.

Deploying code from a private repository to a VPS is something a lot of developers sort of know how to do — but most tutorials either rely on personal SSH keys or Personal Access Tokens. That works, but it gives your server much more access than it actually needs.

In this guide you’ll learn how to set up a repository-specific SSH deploy key for your VPS so you can:

  • Clone your private repository securely
  • Pull updates without storing personal credentials on the server
  • Keep production access scoped narrowly and safely

This method is slightly more advanced than a basic SSH clone, but it’s well worth it if you care about security and clean operations.


What you’ll learn

  • How to create repository-specific SSH deploy keys
  • Why deploy keys are more secure than personal credentials
  • How to configure SSH for multiple GitHub identities
  • The right way to structure your deployment directory
  • How to maintain and rotate deploy keys safely

Time required: ~10–20 minutes
Skill level: Beginner to intermediate (comfortable with SSH and basic Linux)
What you’ll need: SSH access to your VPS with sudo privileges and administrator access to your GitHub repository

Prerequisite: This tutorial assumes you already have SSH access to your server. If you haven't set up your firewall yet, I recommend checking out my guide on securing SSH with UFW first.


Why This Matters

There are several ways to authenticate to GitHub from a server:

  • Using your personal SSH key (risky — it ties the server to your personal account)
  • Using a Personal Access Token (works, but provides overly broad access)
  • Using a Repository-Specific Deploy Key (ideal — scoped access)

Deploy keys follow the principle of least privilege: the server gets just enough access to pull the code it needs, no more.


Step 1 — Prepare Your Deployment Environment

First, create a dedicated deployment user.

Rather than cloning as root or your own account, it’s better to use a dedicated user.

sudo adduser yourappname

This creates: - a user with a home directory (/home/yourappname) - a valid login shell - a clean separation of concerns

Create your application directory:

sudo mkdir -p /opt/yourappname
sudo chown yourappname:www-data /opt/yourappname

Switch to the user:

sudo su - yourappname

Create the .ssh directory:

mkdir -p ~/.ssh
chmod 700 ~/.ssh

⚠️ Important Note — User Model

In this guide, we use a regular user with a home directory to simplify deployment and SSH key management.

This is intentional.

An alternative approach is to use a system (non-login) service account (e.g. created with adduser --system) and run the application via systemd.

However, system users: - often have /usr/sbin/nologin as their shell - may not have a usable home directory - are not suitable for interactive steps like sudo su - user or managing ~/.ssh

For small VPS deployments and solo projects, the approach used here is simpler, clearer, and less error-prone.

In more advanced setups, you may separate: - a deploy user (for Git/SSH) - a service user (for running the app)


Why /opt and not /home, /srv, or somewhere else?

TL;DR: /opt makes it immediately obvious what is system-owned and what you deployed yourself.

(… unchanged section …)


Step 2 — Generate a Repository-Specific SSH Deploy Key

mkdir -p ~/.ssh
chmod 700 ~/.ssh

Generate a new SSH key specifically for this repository:

ssh-keygen -t ed25519 -C "github-deploy-key-yourappname" -f ~/.ssh/id_ed25519_deploy_yourappname

Display the public key:

cat ~/.ssh/id_ed25519_deploy_yourappname.pub

Step 3 — Register the Deploy Key on GitHub

(unchanged)


Step 4 — Configure SSH on the Server

(unchanged)


Step 5 — Clone the Repository

cd /opt/yourappname
git clone git@github-deploy:yourusername/yourappname.git

Step 6 — Verify Permissions and Security

(unchanged)


Step 7 — Pulling Updates Later

sudo su - yourappname
cd /opt/yourappname/yourappname
git pull origin main

Restart service if needed:

sudo systemctl restart yourappname

Step 8 — Key Rotation and Maintenance

(unchanged)


Common Pitfalls & Quick Checks

(unchanged)


Wrapping Up

Using a repository-specific deploy key gives you a clean, secure way to pull private code onto a server without exposing broad access credentials.

The principle is simple: give each server exactly the access it needs — nothing more.

If this deploy key is ever compromised, you can revoke it on GitHub without affecting your other repositories or your personal access.

If you found this helpful, you might also want to check out the other articles in this series: