Back to blog
Mar 29, 2025
16 min read

Roll Your Own Git Server: Gitea on Proxmox (and Cloudflare Zero Trust)

This guide walks through the process of setting up a personal Git server using Gitea on Proxmox, secured with Cloudflare Zero Trust. It's about taking control of your workflow, and here's how you can do it.

Why Gitea? Taking Control of Your Git Workflow

I wanted a self-hosted Git solution, and Gitea seemed like a good balance between simplicity and functionality. Plus, it’s lightweight, which is perfect for my Proxmox LXC.

Step 1: Installing Gitea with Proxmox Helper Scripts

Proxmox VE is fantastic, and the community has made things even easier with helper scripts. These scripts automate the creation and basic configuration of LXC containers for various applications, including Gitea.

To get started, log in to your Proxmox host and run the Gitea LXC script.

# Example command - find the exact one for Gitea from the helper scripts repo
bash -c "$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/gitea.sh)"

The script will ask you some questions. You can generally accept the defaults, but pay attention to the network settings. I recommend setting a static IP address for the container, if you do you will also to configure the gateway IP adress, in my case is my routers ip. You’ll also set the container’s resources (CPU cores, RAM, disk size) – Gitea is pretty lightweight, so you don’t need much to start.

Running the Proxmox Helper Script for Gitea

Step 2: Initial Access and Noting the Details

Once the script finishes, the container will boot up, and Gitea will be running. The script usually outputs the IP address and port Gitea is listening on (typically port 3000).

Make a note of this internal IP address and port (e.g., 192.168.0.99:3000). You’ll need it for the next step.

Console output showing Gitea IP and Port

Step 3: Exposing Gitea with a Cloudflare Tunnel (HTTP)

We want to access Gitea from anywhere, but opening firewall ports isn’t ideal. Cloudflare Zero Trust Tunnels solve this by creating a secure, outbound-only connection from your homelab to Cloudflare’s edge.

If you don’t already have a Cloudflare service running, you’ll need to create one. You can either:

  • Use the helper script (recommended).
  • Manually set up an LXC container and install cloudflared by following these steps:

1. Set Up the Cloudflare Tunnel

  1. Log in to your Cloudflare dashboard. Go to Zero TrustAccessTunnels.
  2. Create a new tunnel. Name it something descriptive, like gitea-server.
  3. Install the connector. Cloudflare will provide installation commands for cloudflared. Run them inside your Cloudflare LXC container.

2. Configure a Public Hostname: This is how you’ll access Gitea via the web:

  • Add a new public hostname.
  • Choose a subdomain (e.g., git.yourdomain.com).
  • Set the Service Type to HTTP.
  • Point it to your Gitea LXC’s internal IP and port (e.g., http://192.168.0.99:3000).
  • Save the hostname and the tunnel configuration.
Configuring the HTTP public hostname in Cloudflare Tunnels

Now, you should be able to access https://git.yourdomain.com (or whatever subdomain you chose) in your browser, and it will load the Gitea setup page!

Step 4: Configuring Gitea

Accessing your Gitea instance via the Cloudflare URL (git.yourdomain.com) will present you with the initial configuration page. Here’s what I did:

  1. Database: For a personal setup or small team, SQLite3 is perfectly fine and the simplest option. If you anticipate heavy usage or many users down the line, consider setting up PostgreSQL or MySQL separately.
  2. General Settings:
    • Site Title: Give your Gitea instance a name.
    • Server Domain: This should be the domain you set up in the Cloudflare tunnel (e.g., git.yourdomain.com).
    • Gitea Base URL: This should be the full URL, including http:// or https:// (e.g., https://git.yourdomain.com/). Important: Since Cloudflare handles the HTTPS, use https:// here if your tunnel is set up correctly.
Gitea initial configuration screen
  1. Optional Settings (Admin Account & More):
    • Scroll down to create your Admin Account. Choose a secure username and password. Write these down!
    • Under “Server and Other Service Settings,” I recommend disabling self-registration if it’s just for you or a known group. This prevents random sign-ups.
    • Review other settings, but defaults are generally okay to start.
Gitea admin account creation fields Disabling user self-registration

Click “Install Gitea”. It might take a minute or two. Once done, you’ll be redirected to the login page or logged in directly as the admin user.

Step 5: User Management - Create Your Day-to-Day User

While you can use the admin account for everything, it’s better practice to create a regular user account for your daily Git activities.

  1. Log in as the admin user you just created.
  2. Click the site administration icon (usually a wrench or gear) in the top right.
  3. Navigate to User Accounts.
  4. Click Create User.
  5. Fill out the details for your regular user account (username, email, initial password).
Navigating to user creation in Gitea admin panel Gitea new user creation form

Now, sign out of the admin account and log in as the new user you just created. Gitea will likely prompt you to change the initial password immediately. Do that.

Step 6: Adding Your SSH Key

To push and pull repositories using Git over SSH (the recommended way), you need to add your public SSH key to your Gitea account.

  1. Make sure you’re logged in as your regular user.
  2. Click your avatar/profile icon in the top right corner and select Settings.
  3. Go to the SSH / GPG Keys tab.
Location of the Add SSH Key button
  1. Click Add Key.
  2. Give the key a recognizable Key Name (e.g., “My Laptop”).
  3. Paste your public SSH key into the Content box. You can usually get this by running:
    cat ~/.ssh/id_ed25519.pub # Or id_rsa.pub if you use RSA
    
    (Pro-tip: On Linux with Wayland or X11, you can use tools like wl-copy or xclip to copy directly: cat ~/.ssh/id_ed25519.pub | wl-copy)
  4. Click Add Key.

You should see a confirmation that the key was added successfully.

Step 7: Setting Up the SSH Tunnel (Cloudflare Again)

Just like we tunneled HTTP traffic, we need to tunnel SSH traffic. This requires another entry in your Cloudflare tunnel configuration.

  1. Go back to your tunnel configuration in the Cloudflare Zero Trust dashboard (Access -> Tunnels -> select your tunnel -> Configure).
  2. Go to the Public Hostnames tab.
  3. Click Add a public hostname.
  4. Subdomain: Choose a different subdomain specifically for SSH (e.g., git-ssh.yourdomain.com). This keeps things clean.
  5. Service:
    • Type: SSH
    • URL: ssh://<GITEA_LXC_IP>:22 (e.g., ssh://192.168.0.99:22). Make sure this is the IP address of your Gitea LXC container and the standard SSH port 22.
  6. Save the hostname.
Configuring the SSH public hostname in Cloudflare Tunnels

Step 8: Configuring Your Local SSH Client

Your computer’s SSH client needs to know how to use this Cloudflare tunnel when connecting to your Gitea SSH domain.

  1. Install cloudflared on your local machine. This is the machine you’ll be running git clone, git push, etc., from.

    • On Debian/Ubuntu: sudo apt update && sudo apt install cloudflared
    • For other systems (macOS, Windows, other Linux distros), check the official Cloudflare documentation
  2. Log in cloudflared: Run cloudflared login in your terminal and follow the browser prompts to authenticate with your Cloudflare account.

  3. Edit your SSH config file: Open ~/.ssh/config in a text editor (create it if it doesn’t exist: nano ~/.ssh/config).

  4. Add the following block, replacing git-ssh.yourdomain.com with the SSH subdomain you created:

    Host git-ssh.yourdomain.com
      ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
    
    • Important: Verify the path to cloudflared. Run which cloudflared in your terminal to find the correct path and update the ProxyCommand line if necessary (it might be /usr/bin/cloudflared or something else).
SSH config entry using cloudflared proxy command

Save the file (Ctrl+O, Enter in nano) and exit (Ctrl+X).

Step 9: Pointing Gitea to the Correct SSH Domain

Gitea needs to tell users the correct SSH clone URL, which now involves our special SSH tunnel domain.

  1. SSH into your Gitea LXC container.

  2. Edit the Gitea configuration file. The exact path might vary slightly depending on the helper script, but it’s usually /etc/gitea/app.ini or /var/lib/gitea/custom/conf/app.ini. Use nano or your preferred editor:

    sudo nano /etc/gitea/app.ini
    
  3. Find the [server] section.

  4. Change the SSH_DOMAIN variable to match the subdomain you created for the SSH tunnel:

    [server]
    ; Domain name to be exposed in SSH clone URL
    ; Default is %(DOMAIN)s
    SSH_DOMAIN = git-ssh.yourdomain.com
    
    Editing the SSH_DOMAIN in Gitea's app.ini file
  5. Save the file (Ctrl+O, Enter in nano) and exit (Ctrl+X).

  6. Restart the Gitea service for the change to take effect:

    sudo systemctl restart gitea
    

Tip: The app.ini file has tons of configuration options. Check out the Gitea documentation for more: https://docs.gitea.com/next/administration/config-cheat-sheet

Step 10: Testing Time! Create and Clone a Repo

The moment of truth!

  1. Go to your Gitea instance in the browser (https://git.yourdomain.com).
  2. Log in as your regular user.
  3. Create a new repository (click the ”+” icon -> New Repository). Give it a name (e.g., test-repo), initialize it with a README, and create it.
  4. On the repository page, find the clone URL dropdown. Make sure SSH is selected. Copy the SSH URL. It should look like [email protected]:YourUsername/test-repo.git.
Copying the SSH clone URL from the Gitea repository page
  1. Open a terminal on your local machine (where you configured ~/.ssh/config and added your key to Gitea).
  2. Run the git clone command with the copied URL:
    git clone [email protected]:YourUsername/test-repo.git
    
  3. If this is the first time connecting via SSH through the tunnel, you might get a host authenticity warning. Type yes to continue.

If everything is set up correctly, the repository should clone successfully to your local machine!

Try making a change, committing, and pushing:

cd test-repo
echo "Testing" >> README.md
git add README.md
git commit -m "Test push"
git push origin main

This should also work seamlessly.

Security Doesn’t Stop Here

Okay, so we have a working Gitea setup accessible via secure Cloudflare tunnels. That’s a great start! But here are a couple more things to seriously consider:

  1. Enable Two-Factor Authentication (2FA): Go into your user settings (and the admin settings!) in Gitea and set up 2FA. This adds a significant layer of security to your accounts.
  2. Cloudflare Access Policies: For even tighter control, go back to the Cloudflare Zero Trust dashboard. Under Access -> Applications, you can create an Application.
    • Choose “Self-hosted”.
    • Link this application to the hostnames you created for your tunnel (git.yourdomain.com and git-ssh.yourdomain.com).
    • Configure policies to define who can access these hostnames. You can require users to log in via GitHub, Google, email one-time passcodes, etc., and restrict it only to specific email addresses (like your own). This adds an authentication layer before anyone even reaches your Gitea login page or the SSH port via the tunnel.

Conclusion: Your Own Little Git Corner

And there you have it! A self-hosted Gitea server running smoothly in a Proxmox LXC, accessible from anywhere thanks to Cloudflare Tunnels. It took a few steps, but now you have full control over your Git workflow, repositories, and user access.

This setup works great for personal projects or small teams. It’s a bit more involved than just signing up for GitHub, but the control and learning experience are worth it, in my opinion.

Let me know if you try this out or have any suggestions! Happy coding!