riksi Start a project

Lesson 02 LearningGuides

Set up Git on your server and deploy with a push

Updated 3 min read By

You’re still uploading files to your server by hand, and you’d like one command to do it for you. Git on your server lets you deploy a website with git push, instead of uploading files by hand. The set-up I’d start with is a bare repository on the server with a post-receive hook. The hook is a script that Git runs after each push, and it copies the pushed code into the web folder.

Does your code already live on GitHub or GitLab? Then you can let the server pull from there instead, with a read-only deploy key.

1. Install Git on the server

# Ubuntu / Debian
sudo apt update && sudo apt install git

# Rocky, AlmaLinux, CentOS Stream, Fedora
sudo dnf install git

git --version

Set your name and email once on each machine you commit from, so your commits are labelled properly. Run git config --global user.name "Your Name" and git config --global user.email "[email protected]". That’s the shortest step in this guide, so enjoy it.

2. Connect with SSH keys, not passwords

On your own computer, create a key if you don’t have one. Then copy it to the server. A key pair works like a padlock and its key. The server gets the padlock, and your computer keeps the key.

ssh-keygen -t ed25519 -C "[email protected]"
ssh-copy-id [email protected]
ssh [email protected]   # should log in without a password

I’d use a separate deploy user that owns the site files, not root. Once keys work, turn off password logins in /etc/ssh/sshd_config (PasswordAuthentication no). That stops a whole type of attack, like password guessing.

3. Option A: push to the server

On the server, create a bare repository outside the web root. A bare repository holds only the history, with no working files. It remembers every commit, but it has no project files you can open.

mkdir -p ~/repos/site.git && cd ~/repos/site.git
git init --bare --initial-branch=main

Next, add the hook. It runs after every push and checks out the main branch into the live folder. Create ~/repos/site.git/hooks/post-receive with this content.

#!/bin/sh
TARGET=/var/www/example.com
GIT_DIR=/home/deploy/repos/site.git
BRANCH=main

while read oldrev newrev ref; do
  if [ "$ref" = "refs/heads/$BRANCH" ]; then
    git --work-tree="$TARGET" --git-dir="$GIT_DIR" checkout -f "$BRANCH"
    echo "Deployed $BRANCH to $TARGET"
    # e.g. cd "$TARGET" && composer install --no-dev --optimize-autoloader
  fi
done

Then make the hook executable.

chmod +x ~/repos/site.git/hooks/post-receive

On your computer, add the server as a remote and push.

git remote add live [email protected]:repos/site.git
git push live main

The .git folder never ends up in the web root, because the history stays in the bare repository.

Be careful: checkout -f overwrites files that the repository tracks. So Git must ignore uploads and any config files that differ per server. Leave those files in place on the server.

4. Option B: pull from GitHub or GitLab

If the repository is hosted somewhere else, create a key on the server. Add it to the repository as a read-only deploy key. A read-only key is like a library card. The server can borrow the code, but it can’t write in it. On GitHub, go to Settings → Deploy keys. On GitLab, go to Settings → Repository → Deploy keys.

ssh-keygen -t ed25519 -f ~/.ssh/deploy_site -N ""
cat ~/.ssh/deploy_site.pub       # paste this into the deploy key settings

git clone [email protected]:example/site.git /var/www/example.com
# later, to deploy:
cd /var/www/example.com && git pull --ff-only

With a clone in the web root, block public access to the .git folder in the server config. If you don’t, anyone can download your source code and history. I wouldn’t skip this step. On Apache, use RedirectMatch 404 /\.git.

Next steps

Both options update files in place. So for a few seconds, the site can be half old and half new. Tools such as Deployer build each release in its own folder, then switch a symlink when it’s ready. CI services such as GitHub Actions or GitLab CI can run tests and then deploy over SSH automatically.

Still, I think the hook above is the smallest step up from FTP, and a good one. I’d get it working on a staging site first. Then you can stop dragging files into an FTP window.

Filed under LearningGuides
Tagged
Share:

Comments

No comments yet. Questions, fixes and better ways are all welcome.

Leave a comment

Your email is never shown. Comments are checked before they appear, so yours may take a little while.

Start a project

Tell us what is
not working.

A few lines is enough. A real person reads every message and replies by email. Or choose the way that suits you.