Skip to main content

Command Palette

Search for a command to run...

Setting Up a Private Gitea Instance on GCP

Updated
4 min read

Managing your own Git server gives full control over repositories while keeping access private. In this post, I document the process of setting up Gitea on a Google Cloud Platform (GCP) e2-micro VM, including the problems encountered and how they were resolved.

Written with assistance from ChatGPT.

Checkout my instance: <https://gitea.9th.fun/>

1. Setting Up the VM

I started with GCP’s Free Tier e2-micro VM:

  • 1 non-preemptible e2-micro VM in a US region

  • 30 GB persistent disk

  • 1 GB outbound data transfer

Firewall setup:

  • Allowed HTTP (80) and HTTPS (443) traffic

  • SSH left open for private access

Static IP:

  • Reserved a static IP for consistent domain mapping

2. Preparing the VM

Before connecting to the VM, generate a SSH key pair for secure authentication.

2.1: Generate an SSH key pair

On Windows (PowerShell or Git Bash):

# Create a folder for keys
mkdir C:\Users\<YOUR_USER>\Keys\gitea

# Generate an ed25519 SSH key pair
ssh-keygen -t ed25519 -C "USERNAME@gitea-vm" -f C:\Users\<YOUR_USER>\Keys\gitea\id_ed25519
  • Optional: Enter a passphrase for extra security.

  • This generates:

C:\Users\<YOUR_USER>\Keys\gitea\id_ed25519       # Private key (keep secure!)
C:\Users\<YOUR_USER>\Keys\gitea\id_ed25519.pub   # Public key (upload to VM)

2.2: Add the public key to the VM

  • During VM creation, paste the public key in the SSH keys section of the GCP Console.

  • Alternatively, after VM creation:

# On VM, create SSH directory for the user
mkdir -p ~/.ssh
echo "<paste-your-public-key-here>" >> ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Files involved:

  • ~/.ssh/authorized_keys → Stores the public keys allowed to connect

  • ~/.ssh/ → SSH directory

2.3: Test SSH connection

On Windows:

ssh -i C:\Users\<YOUR_USER>\Keys\gitea\id_ed25519 USERNAME@<VM_IP>

2.4: Update SSH config for convenience

Edit C:\Users\<YOUR_USER>\.ssh\config:

Host gitea.example.com
  HostName <VM_IP>
  User USERNAME
  IdentityFile C:\Users\<YOUR_USER>\Keys\gitea\id_ed25519
  Port 22

3. Installing Gitea

3.1: Create necessary directories

sudo mkdir -p /var/lib/gitea/{custom,data,log}
sudo chown -R git:git /var/lib/gitea

Directories involved:

  • /var/lib/gitea/custom/ → Custom configs/templates

  • /var/lib/gitea/data/ → App data, database

  • /var/lib/gitea/log/ → Logs

3.2: Download Gitea binary

wget -O /usr/local/bin/gitea https://dl.gitea.io/gitea/1.21.0/gitea-1.21.0-linux-amd64
sudo chmod +x /usr/local/bin/gitea

File involved:

  • /usr/local/bin/gitea → Main Gitea executable

3.3: Create a systemd service at /etc/systemd/system/gitea.service

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

[Service]
RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea
Environment=USER=git HOME=/var/lib/gitea GITEA_WORK_DIR=/var/lib/gitea
ExecStart=/usr/local/bin/gitea web -c /etc/gitea/app.ini

[Install]
WantedBy=multi-user.target

4. Nginx Reverse Proxy Setup

4.1: Create a file /etc/nginx/sites-available/gitea

server {
    listen 80;
    server_name gitea.example.com;

    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

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

4.2: Enable the site and reload Nginx

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

Files involved:

  • /etc/nginx/sites-available/gitea → Nginx config for Gitea

  • /etc/nginx/sites-enabled/gitea → Symlink to enable site

5. Initial Gitea Setup

Files involved:

  • /etc/gitea/app.ini → Main Gitea configuration

  • /var/lib/gitea/data/gitea.db → SQLite database

6. Enabling SSH for Gitea

Update /etc/gitea/app.ini:

[server]
DISABLE_SSH = false
SSH_PORT = 2222
SSH_DOMAIN = gitea.example.com
START_SSH_SERVER = true

Problem faced:

  • Ports <1024 require root; Gitea runs as non-root.

  • Service failed with: Failed to start SSH server: listen tcp :22: bind: permission denied.

Solution:

  • Use a non-privileged SSH port (e.g., 2222).

  • Restart Gitea to activate SSH:

sudo systemctl restart gitea

7. Configuring Windows SSH

Update C:\Users\<YOUR_USER>\.ssh\config:

Host gitea.example.com
  User git
  IdentityFile C:\Users\<YOUR_USER>\Keys\gitea\id_ed25519
  Port 2222

Test connection:

ssh -v git@gitea.example.com

8. Firewall & Networking

  • Open TCP port 2222 in GCP firewall rules.

  • Cloudflare only proxies HTTP/HTTPS → cannot proxy SSH.

  • Use VM public IP for SSH pushes.

Example Git remote:

git remote set-url gitea ssh://git@gitea.example.com:2222/USERNAME/<repo_name>.git
git push -u gitea master

9. Final Notes

  • Private Gitea: Only admin can create accounts (DISABLE_REGISTRATION = true).

  • HTTP/HTTPS: Served via Nginx, optionally protected by Cloudflare.

  • SSH for Git: Non-privileged port (2222), keys registered in Gitea.

  • File paths modified/created:

File/DirectoryPurpose
C:\Users\<YOUR_USER>\Keys\gitea/id_ed25519*SSH keys
~/.ssh/authorized_keysPublic key storage
C:\Users\<YOUR_USER>\.ssh/configSSH config for convenience
/usr/local/bin/giteaGitea executable
/etc/systemd/system/gitea.servicesystemd service definition
/var/lib/gitea/{custom,data,log}Gitea directories
/etc/gitea/app.iniGitea config
/etc/nginx/sites-available/giteaNginx config
/etc/nginx/sites-enabled/giteaNginx symlink

Outcome: Fully functional private Gitea instance on GCP:

  • Web UI via https://gitea.example.com

  • Git push/pull via SSH on port 2222

  • Admin-only registration

  • Secure key-based authentication

Setting Up a Private Gitea Instance on GCP