Skip to main content
TRACK B·DEVELOPER SETUP·Verified June 2026 · Lua 5.4 · ox_lib 3.x
Learning with an AI assistant?
Copies this lesson plus 2026 ground rules (no lua54 'yes', Cfx.re Portal, correct callback signatures) as a ready-to-paste mentor prompt.

From localhost to VPS with Git

Editing files straight on a live server is how beginners take their server down at 2am with no way back. The professional loop is different: you code on your PC, you commit when it works, you push, and the VPS pulls a known-good version. Git is the time machine that lets you roll back the moment a deploy breaks. This lesson wires that loop end to end for one resource.

You'll build
A safe deploy loop: develop on your PC, commit with GitHub Desktop, push to a private repo, then pull onto your VPS and restart, with no secrets ever leaving your machine.
Time
~30 minutes.
You need
GitHub Desktop set up (the version-control lesson), a GitHub account, and a VPS you can reach over SSH.
You'll learn
A private repo -> .gitignore for secrets -> clone on the VPS -> the edit/commit/push/pull/restart loop -> roll back a bad deploy
BEFORE YOU START

Build it

Add a .gitignore before the first commit

Secret files are invisible to Git from the start.

Open your resource folder in VS Code and create a file named .gitignore at its root. List anything that holds a secret or is machine-specific:

code
# secrets and machine-specific files, never committed
*.env
license-key.txt
db-creds.txt
config.secret.lua
node_modules/

Keep real config out of code. Instead of writing a key into a committed file, set it as a convar in server.cfg (which lives on the server and is never in the repo) and read it at runtime. The convars lesson goes deep on this, but here is the shape so the secrets claim is not hand-waved:

code
-- server.cfg (on the VPS, NOT in the repo):
--   set my_license_key "your-real-key-here"

-- server.lua (in the repo, no secret in sight):
local key = GetConvar('my_license_key', 'unset')
print('license key loaded:', key ~= 'unset')

The code ships the variable name, not the value. Each machine supplies its own value through its own server.cfg.

Publish a PRIVATE repository

Your code is on GitHub, private, with the secret files excluded.

In GitHub Desktop, commit your work, then choose Publish repository. Crucial: untick Keep this code private only if you truly want the world to read it. For a server, leave it private.

Install Git on the VPS and clone into resources

A first copy of the resource exists on the VPS, pulled from GitHub.

Open an SSH session to your VPS (on Windows, type ssh user@your-vps-ip in PowerShell or Windows Terminal; or use the browser-based console in your VPS provider's control panel). Install Git if it is missing (sudo apt update && sudo apt install -y git on Ubuntu/Debian). Because the repo is private, GitHub will not accept your account password on clone. You need a credential the VPS can use. The fastest one to create is a fine-grained personal access token:

  1. On github.com, go to Settings -> Developer settings -> Personal access tokens -> Fine-grained tokens -> Generate new token.
  2. Scope it to Only select repositories and pick this one repo. Under Repository permissions, set Contents to Read-only. That token can pull this repo and nothing else.
  3. Set a short expiry (30 to 90 days) and copy the token once. GitHub shows it a single time.

Now clone into the server's resources folder. When Git asks for a username, enter your GitHub username; when it asks for a password, paste the token (not your real password):

code
cd /home/fivem/server-data/resources
git clone https://github.com/your-username/your-resource.git qu_deploy_demo

The last word, qu_deploy_demo, is the folder name Git creates on the VPS (it overrides the repo's own name). Every command later in this lesson uses that exact name, so if you pick a different folder name, swap it in everywhere qu_deploy_demo appears.

A read-only token is the safer choice for a deploy box: even if the VPS is compromised, the attacker can only read one repo, never push or touch your account. An SSH deploy key (a keypair added to the repo's Deploy keys) achieves the same scoping and avoids token expiry if you prefer keys. Then ensure qu_deploy_demo in server.cfg and restart the server once so it loads.

Run the update loop

A change made on your PC reaches the VPS with two commands and a restart.

This is the loop you repeat forever. On your PC: make the change, test locally, then commit and push in GitHub Desktop. On the VPS: pull and restart.

On the VPS, inside the resource folder:

code
cd /home/fivem/server-data/resources/qu_deploy_demo
git pull

Then in the txAdmin Live Console:

code
restart qu_deploy_demo

Roll back a bad deploy

You can return the VPS to the last working commit in seconds.

A deploy breaks the server. Stay calm: Git remembers every version. On the VPS, see recent commits and reset to the last good one:

code
git log --oneline -n 5
git reset --hard <good_commit_hash>

git log --oneline -n 5 lists your last five commits, newest first; each line starts with a short hash like a1b2c3d followed by its message. Replace <good_commit_hash> with the short hash from the line of the last commit you know worked (read the messages to find it). Do not type the angle brackets.

Then restart qu_deploy_demo. The resource is back to that exact known-good state. This is why you push working code in small commits: every commit is a save point you can return to.

Keep reading the full lesson

Sign in to start, then unlock every step of this lesson and the full FiveM School with a membership.

Still ahead in this lesson
  • How it works
  • If something went wrong
  • What you can do now
  • Try it yourself

The remainder of Deploy changes from localhost to your server is available to FiveM School members.