12 min read

How to Self-Host Gitea and Access Your Git Server from Anywhere

Run your own private Git server with Gitea on Docker Compose. Expose the web interface and SSH cloning from anywhere using two Localtonet tunnels.

🐙 Gitea · Self-Hosted Git · Remote Access · Docker · 2026

How to Self-Host Gitea and Access Your Git Server from Anywhere

Gitea is a lightweight, open-source Git service you can run on your own hardware. You get private repositories, pull requests, issue tracking, and a web interface similar to GitHub with no monthly fees, no storage limits, and no third party holding your code. This guide covers installing Gitea with Docker Compose, completing the setup wizard, and making both the web interface and SSH cloning work from anywhere using Localtonet.

🗂️ Private repositories 🔀 Pull requests and issues 🐳 Docker Compose setup 🌍 Web and SSH access from anywhere

What Is Gitea?

Gitea is an open-source Git hosting platform written in Go. It runs as a single binary with minimal resource requirements, making it practical on a home server, a Raspberry Pi, or a small VPS. The web interface covers everything you would expect from a modern Git platform: repository browsing, pull requests, code review, issue tracking, milestones, wikis, release management, and webhooks.

The main reason people self-host Gitea instead of using GitHub or GitLab is control. Your repositories live on your hardware. You set the storage limits. You decide who has access. There are no account suspensions, no policy changes, and no subscription required to keep private repositories private.

Self-Hosted Gitea
  • Complete ownership of your code
  • Unlimited private repositories
  • No storage limits beyond your hardware
  • No account bans or policy enforcement
  • Works fully offline on a local network
  • Free for any number of users
GitHub / GitLab.com
  • Code stored on third-party servers
  • Storage and bandwidth limits on free plans
  • Subject to platform policy changes
  • Private repos require a paid plan on some tiers
  • No offline access
Very lightweight Runs comfortably on a Raspberry Pi 3 or a 512 MB VPS. Written in Go with no heavy runtime requirements.
🔀 Full Git workflow Pull requests, code review, branch protection, merge strategies, and webhooks. Everything a small team needs.
🔌 CI/CD integrations Works with Drone CI, Jenkins, Woodpecker CI, and GitHub Actions-compatible runners via Gitea Actions.
🗄️ Multiple database options SQLite for simple single-user setups. PostgreSQL or MySQL for teams and production environments.
🐳 Docker-native Official image on Docker Hub. Persistent volumes keep your data safe across container restarts and upgrades.
📦 Package registry Built-in package registry supporting npm, PyPI, Maven, Docker images, and more. No extra service needed.

Install Gitea with Docker Compose

Docker Compose is the simplest and most portable way to run Gitea. The setup below uses SQLite as the database, which is perfectly fine for personal use and small teams. If you expect many concurrent users or heavy repository traffic, replace SQLite with PostgreSQL an example is included at the end of this section.

1

Create the project directory

mkdir gitea && cd gitea
2

Create the Docker Compose file

Create a docker-compose.yml file with the following content. Note the SSH port mapping: Gitea's internal SSH runs on port 22 inside the container, mapped to port 2222 on the host to avoid conflicting with the host's own SSH server.

networks:
  gitea:
    external: false

services:
  server:
    image: docker.gitea.com/gitea:latest
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: unless-stopped
    networks:
      - gitea
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "2222:22"
3

Start Gitea

docker compose up -d
docker compose ps

Gitea is now running at http://localhost:3000. Open that address in your browser to continue with the setup wizard.

Optional: PostgreSQL for team or production use

Add a PostgreSQL service to your Compose file if you need better performance under concurrent load.

networks:
  gitea:
    external: false

services:
  server:
    image: docker.gitea.com/gitea:latest
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE=postgres
      - GITEA__database__HOST=db:5432
      - GITEA__database__NAME=gitea
      - GITEA__database__USER=gitea
      - GITEA__database__PASSWD=changeme
    restart: unless-stopped
    networks:
      - gitea
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "2222:22"
    depends_on:
      - db

  db:
    image: postgres:16
    restart: unless-stopped
    environment:
      - POSTGRES_USER=gitea
      - POSTGRES_PASSWORD=changeme
      - POSTGRES_DB=gitea
    networks:
      - gitea
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
Change the database password

Replace changeme with a strong password before starting the stack. Use the same password in both the server and db service definitions.

Complete the Setup Wizard

The first time you open Gitea in your browser, it runs an installation wizard. Most settings can stay at their defaults, but a few need attention.

1

Database settings

If you are using the SQLite-only Compose file, select SQLite3 as the database type. For the PostgreSQL setup, select PostgreSQL and enter db as the host, port 5432, and the credentials from your Compose file.

2

SSH server domain and port

Set SSH Server Domain to localhost for now. You will update this after the Localtonet tunnel is running. Set SSH Server Port to 2222 to match the host port in the Compose file.

3

Gitea base URL

Set Gitea Base URL to http://localhost:3000 for now. You will update this after the HTTP tunnel is set up and you have a public URL.

4

Create the administrator account

Scroll to the bottom of the wizard and fill in the Administrator Account Settings. Choose a username, a strong password, and an email address. Click Install Gitea. Gitea redirects you to the dashboard and your server is ready.

Access the Gitea Web Interface from Anywhere

Gitea's web interface runs on port 3000. To reach it from outside your local network, create an HTTP tunnel in Localtonet. The tunnel gives you a public HTTPS URL and handles TLS automatically. Gitea itself requires no changes.

1

Install and authenticate Localtonet on the host machine

curl -fsSL https://localtonet.com/install.sh | sh
localtonet --authtoken <YOUR_TOKEN>
2

Create an HTTP tunnel for port 3000

Log in to the Localtonet dashboard, go to Tunnels → New Tunnel, select HTTP, set local IP to 127.0.0.1 and port to 3000. Click Create. The dashboard generates a public HTTPS URL such as https://abc123.localto.net.

3

Update the Gitea base URL

Open Gitea, go to Site Administration → Configuration and update the Root URL to your Localtonet HTTPS URL. Alternatively, edit the config file directly on the host:

# The app.ini is stored inside the data volume
nano ./data/gitea/conf/app.ini

Find the [server] section and update these two values:

[server]
DOMAIN           = abc123.localto.net
ROOT_URL         = https://abc123.localto.net/

Restart Gitea to apply the change:

docker compose restart server

Your Gitea web interface is now reachable at the HTTPS URL from any browser, anywhere in the world.

SSH Git Cloning from Anywhere

The web interface handles browsing and management, but developers also need to push and pull over SSH. Gitea's SSH server runs on port 2222 on the host. Create a second Localtonet TCP tunnel for this port.

1

Create a TCP tunnel for port 2222

In the Localtonet dashboard, go to Tunnels → New Tunnel, select TCP, set local IP to 127.0.0.1 and port to 2222. Click Create. The relay address will look like example.localto.net:33XX.

2

Update the SSH domain in Gitea config

Open ./data/gitea/conf/app.ini and update the SSH settings so Gitea shows the correct clone URL in the web interface.

[server]
DOMAIN           = abc123.localto.net
ROOT_URL         = https://abc123.localto.net/
SSH_DOMAIN       = example.localto.net
SSH_PORT         = 33221
docker compose restart server

Now when you open any repository in Gitea and click the SSH clone button, the URL shown already contains the relay address and port. Clone a repository from any machine:

git clone ssh://git@example.localto.net:33221/youruser/yourrepo.git
Add your SSH key to Gitea first

SSH cloning requires your public key to be registered in Gitea. Go to Settings → SSH and GPG Keys → Add Key and paste the contents of your ~/.ssh/id_ed25519.pub (or id_rsa.pub) file. Gitea uses this key to authenticate your git push and git pull commands.

Keep Everything Running After a Reboot

The Docker Compose file already has restart: unless-stopped on the Gitea container, so it comes back automatically when Docker starts. To also bring the Localtonet tunnels back after a reboot, register Localtonet as a systemd service on the host machine:

sudo localtonet --install-service --authtoken <YOUR_TOKEN>
sudo localtonet --start-service --authtoken <YOUR_TOKEN>

Confirm both services are running:

docker compose ps
systemctl status localtonet

After this, a full power cycle brings Gitea and both tunnels back without any manual steps. Your Git server and its public URLs are available again within seconds of the machine booting.

Security Recommendations

🔑 Disable registration after creating your accounts

A publicly reachable Gitea instance with open registration can be found and abused by bots. Once you and your team have created accounts, go to Site Administration → Configuration → User settings and disable Allow Self-Registration. New users can only be added by an administrator from that point on.

🔒 Use SSH keys, not passwords, for Git operations

Password-based Git authentication over HTTPS is less secure and more friction than SSH keys. Add your SSH public key to Gitea and use git clone ssh://... URLs for all push and pull operations. You can also disable password authentication for Git over HTTP in the Gitea admin settings.

🌍 Do not bind port 3000 or 2222 to a public interface

The Compose file above does not specify a host IP for the port bindings, which means they listen on all interfaces. For a tighter setup, change the port bindings to 127.0.0.1:3000:3000 and 127.0.0.1:2222:22. This ensures only Localtonet (running on the same machine) can reach those ports.

💾 Back up the data volume regularly

All of Gitea's repositories, configuration, and user data live in the ./data directory. Back this directory up regularly to an external location. A simple approach is a daily cron job that tars the directory and copies it to a remote storage service.

🔐 Add Localtonet SSO for an extra login layer

Enable Single Sign-On on your HTTP tunnel in the Localtonet dashboard. Anyone reaching your Gitea URL must authenticate via Google, GitHub, Microsoft, or GitLab before the Gitea login page even loads. This protects Gitea from brute-force login attempts on the public URL.

Frequently Asked Questions

Can I run Gitea on a Raspberry Pi?

Yes. Gitea is written in Go and compiles to a single binary for ARM and ARM64. The official Docker image supports both architectures. A Raspberry Pi 3 or 4 handles Gitea well for personal use and small teams. Use SQLite as the database to keep resource usage minimal.

Will I lose my repositories if I update the Docker image?

No, as long as you use a volume for the data directory as shown in the Compose file. Pull the new image and recreate the container the data volume persists. Always back up the ./data directory before upgrading, just in case.

Can I migrate my GitHub or GitLab repositories to Gitea?

Yes. Gitea has a built-in migration tool under Create → Migrate Repository. It supports GitHub, GitLab, Bitbucket, Gogs, and plain Git URLs. For GitHub migrations, you can provide a personal access token to also import issues, pull requests, labels, and milestones.

The Localtonet relay address changes. How do I keep a stable clone URL?

Reserve a fixed port for the TCP tunnel via Add-ons → Reserved Ports in the Localtonet dashboard. For the web interface, attach a custom domain to the HTTP tunnel. Both options give you a permanent address that never changes between restarts. Check out our custom domain guide for setup instructions.

Can I use Gitea Actions for CI/CD?

Yes. Gitea Actions is built into Gitea and is compatible with GitHub Actions syntax. You need to run a separate act_runner process to execute the workflow jobs. The runner can run on the same machine as Gitea or on a separate host. Enable Gitea Actions under Site Administration → Configuration → Repository settings.

Is Gitea a good replacement for GitHub for a small team?

For most small team workflows code review, pull requests, issue tracking, CI/CD via webhooks or Gitea Actions, yes. The features that Gitea does not replicate are GitHub-specific things like GitHub Pages, GitHub Marketplace integrations, and the social discovery features. If your team mainly needs a private code host with a familiar workflow, Gitea covers it well.

Your Own Private Git Server, Accessible from Anywhere

Run Gitea with Docker Compose, open two Localtonet tunnels, and your team gets a private Git server with a public web interface and SSH cloning from any location in the world.

Create Free Localtonet Account →

Localtonet is a secure multi-protocol tunneling and proxy platform designed to expose localhost, devices, private services, and AI agents to the public internet supporting HTTP/HTTPS tunnels, TCP/UDP forwarding, mobile proxy infrastructure, file server publishing, latency-optimized game connectivity, and developer-ready AI agent endpoint exposure from a single unified control plane.

support