Innovate | Connect | Transform
ContactService statusUSD $

GICT knowledge base

Build Your Own GitHub in 10 Minutes: A Gitea VPS Setup That Actually Works

Published

Git

GitHub and GitLab charge for private repositories on team plans. If you run even a small dev shop, you are bleeding money on plans you do not need. One Ubuntu VPS, Gitea, and about ten minutes gives you your own private GitHub. Zero monthly fees. Full control.

This is a step-by-step. I ran through every command below on a live VPS and it worked without surprises.

What You Need

A VPS with Ubuntu 22.04 or 24.04. SQLite is built into Gitea, so you do not need MySQL or PostgreSQL. 1GB RAM is enough for light use. 2GB is comfortable.

You also need a domain name. If you do not have one, read the next section. If you do have one, skip ahead.

No Domain? Use nip.io Instead

nip.io is a free wildcard DNS service. It takes any subdomain and resolves it to a given IP address. No account needed, no DNS management, no propagation waiting.

If your VPS IP is 1.2.3.4, then `git.1-2-3-4.nip.io` resolves to 1.2.3.4 automatically. Replace 1.2.3.4 with your actual VPS IP for the rest of this guide.

The nip.io domain works with Let’s Encrypt TLS certificates just like any regular domain. Your readers will see a normal HTTPS lock icon in the browser.

If you prefer to use your own domain instead, replace every `git.X-X-X-X.nip.io` reference below with your domain. The steps are identical.

Install the Binary

Gitea ships as a single binary. No database to install, no dependencies to fight with. Download the latest release from GitHub.

# Download Gitea 1.26.2 (check github.com/go-gitea/gitea/releases for latest)
cd /tmp
curl -L -o gitea https://github.com/go-gitea/gitea/releases/download/v1.26.2/gitea-1.26.2-linux-amd64
chmod +x gitea
sudo cp gitea /usr/local/bin/gitea
sudo chown root:root /usr/local/bin/gitea

Verify it works:

gitea --version
# Output: gitea version 1.26.2 built with go1.26.3-X:jsonv2 : bindata, sqlite, sqlite_unlock_notify

Create the Git User and Directories

Gitea should not run as root. Create a dedicated system user.

sudo useradd --system --comment "Gitea" --create-home --shell /bin/bash git
sudo mkdir -p /var/lib/gitea/{data,log,repositories}
sudo chown -R git:git /var/lib/gitea
sudo chmod -R 750 /var/lib/gitea

The data directory holds your SQLite database and all repository files. The repositories directory is where Git stores your actual code.

Configure Gitea

Gitea needs a config file before it starts. Create it at /etc/gitea/app.ini.

sudo mkdir -p /etc/gitea
sudo chown git:git /etc/gitea
sudo chmod 750 /etc/gitea

Write the config. Replace `git.YOUR_VPS_IP.nip.io` with your actual nip.io address.

APP_NAME = Gitea
RUN_MODE = prod

[server]
PROTOCOL         = http
DOMAIN           = git.YOUR_VPS_IP.nip.io
ROOT_URL         = https://git.YOUR_VPS_IP.nip.io/
HTTP_PORT        = 3000
DISABLE_SSH      = true
SSH_PORT         = 22
START_SSH_SERVER = false
LFS_START_SERVER = true
APP_DATA_PATH    = /var/lib/gitea/data

[database]
DB_TYPE  = sqlite3
PATH     = /var/lib/gitea/data/gitea.db

[security]
INSTALL_LOCK          = false
SECRET_KEY           = CHANGEME-replace-with-random-secret
INTERNAL_TOKEN       = CHANGEME-replace-with-random-token
PASSWORD_HASH_ALGO   = pbkdf2
MIN_PASSWORD_LENGTH  = 8

[log]
MODE      = console
LEVEL     = info
ROOT_PATH = /var/lib/gitea/log

Generate random secrets with:

openssl rand -hex 32

Copy the output into SECRET_KEY and INTERNAL_TOKEN.

Set Up the Systemd Service

Systemd keeps Gitea running and starts it on boot. Create the service file:

sudo nano /etc/systemd/system/gitea.service

Paste this:

[Unit]
Description=Gitea (Git with a cup of tea)
After=network.target

[Service]
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target

Enable and start it:

sudo systemctl daemon-reload
sudo systemctl enable gitea
sudo systemctl start gitea

Check it is running:

sudo systemctl status gitea --no-pager

Look for “active (running)” in the output. If it failed, check the logs with:

sudo journalctl -u gitea --no-pager -n 30

The most common failure is port 3000 already in use or permission denied on the data directories. Both are in the troubleshooting section at the end.

Run the Web Installer

Open your browser and go to http://YOUR_VPS_IP:3000/. You see the Gitea installation wizard. Fill in these fields:

  • Database Type: SQLite3 (default, no setup needed)
  • Repository Root Path: /var/lib/gitea/repositories
  • Run As Username: git (pre-filled, do not change)
  • Domain: git.YOUR_VPS_IP.nip.io (your nip.io address)
  • HTTP Port: 3000
  • Application URL: https://git.YOUR_VPS_IP.nip.io/
  • Administrator Username: pick a username for your admin account
  • Administrator Password: strong password, minimum 8 characters
  • Administrator Email: [email protected]

Click “Install Gitea”. It takes about 30 seconds. When it finishes you land on the login page. Log in with the admin account you just created.

The installer sets INSTALL_LOCK to true in your app.ini. After this the installer is disabled and only the admin can change settings through the UI.

Set Up HTTPS with nginx and Let’s Encrypt

Set up nginx as a reverse proxy first:

sudo nano /etc/nginx/sites-available/gitea

Paste this, replacing `git.YOUR_VPS_IP.nip.io` with your nip.io address:

server {
    listen 80;
    server_name git.YOUR_VPS_IP.nip.io;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Enable the site and reload nginx:

sudo ln -sf /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/gitea
sudo nginx -t
sudo systemctl reload nginx

Now get a free TLS certificate from Let’s Encrypt:

sudo certbot --nginx -d git.YOUR_VPS_IP.nip.io

Certbot reads the nginx config, adds the certificate, and updates it to HTTPS. All HTTP traffic redirects to HTTPS automatically. Your Gitea instance is now served over TLS with a valid certificate that renews automatically. On a VPS with 1GB RAM, the first certbot run takes about 30 seconds.

Create Your First Repository

After logging in, click the plus icon in the top right corner and select “New Repository”.

Fill in:

  • Repository Name: my-project
  • Private: check this if you do not want it public
  • Initialize Repository: check this to add a README
  • GitIgnore: select your language (e.g. Go, Python, Node)

Click “Create Repository”. You now have a working Git server.

Clone and Push Code

On your local machine, find the HTTPS clone URL on your repository page. It looks like:

https://git.YOUR_VPS_IP.nip.io/your-username/my-project.git

Cloning prompts for your Gitea username and password. Enter them and the repository clones.

For a smoother experience, configure Git to remember your password for one hour:

git config --global credential.helper cache --timeout=3600

Enter your credentials once and Git caches them for the session. No more typing your password on every push.

For permanent storage, use the store helper instead:

git config --global credential.helper store
echo "https://your-username:[email protected]_VPS_IP.nip.io" >> ~/.git-credentials
chmod 600 ~/.git-credentials

Replace your-username and your-password with your actual Gitea credentials. This file is plain text so keep it protected.

Once credentials are set up, cloning and pushing work exactly like GitHub:

git clone https://git.YOUR_VPS_IP.nip.io/your-username/my-project.git
cd my-project
echo "Hello world" > README.md
git add README.md
git commit -m "first commit"
git push origin main

If you see “fatal: could not read Username for ‘https://git.YOUR_VPS_IP.nip.io’: No such device or address” when pushing, your credentials are not saved. Run the credential.helper store commands above to fix this.

Back Up Your Data

Gitea stores everything in /var/lib/gitea. The SQLite database, repository files, and attachments are all in there. Back up the entire directory:

sudo tar -czf gitea-backup-$(date +%Y%m%d).tar.gz /var/lib/gitea
sudo chown $USER:$USER gitea-backup-*.tar.gz

Run this daily with a cron job:

sudo crontab -e

Add this line:

0 3 * * * tar -czf /root/gitea-backup-$(date +\%Y\%m\%d).tar.gz /var/lib/gitea

This runs the backup at 3am every day. Copy the backups off the VPS regularly.

Troubleshooting

Gitea will not start. Run:

sudo journalctl -u gitea --no-pager -n 50

The most common issue is port 3000 already in use. Stop whatever is on that port or change HTTP_PORT in app.ini to 3001.

Permission denied on data directories. Verify the git user owns /var/lib/gitea:

sudo chown -R git:git /var/lib/gitea

Push asks for username and password and fails. Your credentials are not saved. Run:

git config --global credential.helper store
# Then enter this line with your actual credentials:
echo "https://username:[email protected]_VPS_IP.nip.io" >> ~/.git-credentials
chmod 600 ~/.git-credentials

Let’s Encrypt fails to issue a certificate. Verify the nip.io domain resolves to your VPS IP:

ping git.YOUR_VPS_IP.nip.io

If ping resolves to your VPS IP, nginx is proxying correctly and certbot should work. If you see a different IP, your VPS IP in the nip.io address is wrong. Check your VPS public IP with:

curl ifconfig.me

Ready to own your code? InterServer VPS plans starting at $3/month with full root access. No panel fees, no limits on repositories.

Related guides

Account services are unavailable until the production backend is configured.