Deploy with Git on a VPS

2 min read07 November 2026

Git lets you deploy exactly the version you tested, instead of overwriting files by hand over FTP. On a VPS, the simplest approach is a clone in /var/www, updated with git pull. It requires a read-only deploy key, clean permissions and one clear rule: the server never edits the code.

Prepare a deploy key

As the deployment user, for example deploy:

Bash
ssh-keygen -t ed25519 -C "deploy@vps" -f ~/.ssh/deploy_key -N ""
cat ~/.ssh/deploy_key.pub

In GitHub or GitLab, add the public key as a read-only deploy key limited to this repository. A machine account with access to every repository is unnecessary here. Declare the alias:

Configuration
Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/deploy_key
  IdentitiesOnly yes

IdentitiesOnly yes stops SSH from trying other keys. Test with ssh -T [email protected]: the expected message confirms authentication, without a shell.

Clone into /var/www

Bash
sudo mkdir -p /var/www
sudo chown deploy:www-data /var/www
git clone [email protected]:account/repository.git /var/www/app
cd /var/www/app

Do not clone into /root, and avoid serving a directory that contains .git, node_modules or tests directly. For a static site, point Nginx at the public subdirectory. Permissions stay: directories 750, files 640, owner deploy, group www-data.

Update without overwriting

Bash
git fetch --prune
git status
git pull --ff-only

--ff-only refuses an implicit local merge: the update fails instead of creating an unexpected commit. Do not edit files by hand on the server, or the next pull will be blocked. To return to a known state, git log --oneline identifies a healthy commit; after confirming there are no local changes, git reset --hard <commit> replaces the working copy, then restart the service.

A short script avoids omissions:

Bash
#!/bin/sh
set -eu
cd /var/www/app
git pull --ff-only
npm ci --omit=dev
sudo systemctl restart app

Adapt the dependency and restart commands to your stack: composer install --no-dev for PHP, the virtual environment for Python.

Secrets and verification

.env, private keys and backups never go into Git. Create them on the server with chmod 600. A compromised deploy key allows reading the repository, not writing to it: keep that scope and revoke the key if needed.

After deployment, check git log -1 --oneline, systemctl status and a health route with curl. Back up the database before any migration. If the repository is private, test the clone from the VPS before removing the previous deployment: a key problem shows up immediately.

Advertisement

Was this article helpful?

Read next