Setting Up a Private Gitea Instance on GCP
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
Visit
http://gitea.example.comto complete the installation.Use SQLite for simplicity.
Create an admin user.
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
<1024require 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/Directory | Purpose |
C:\Users\<YOUR_USER>\Keys\gitea/id_ed25519* | SSH keys |
~/.ssh/authorized_keys | Public key storage |
C:\Users\<YOUR_USER>\.ssh/config | SSH config for convenience |
/usr/local/bin/gitea | Gitea executable |
/etc/systemd/system/gitea.service | systemd service definition |
/var/lib/gitea/{custom,data,log} | Gitea directories |
/etc/gitea/app.ini | Gitea config |
/etc/nginx/sites-available/gitea | Nginx config |
/etc/nginx/sites-enabled/gitea | Nginx symlink |
✅ Outcome: Fully functional private Gitea instance on GCP:
Web UI via
https://gitea.example.comGit push/pull via SSH on port 2222
Admin-only registration
Secure key-based authentication