Gitea Docker Setup: Host Your Own Lightweight GitHub Alternative

Learn how to deploy Gitea using Docker Compose. A complete guide to hosting your own fast, lightweight, and fully customized GitHub/GitLab alternative.

Prerequisites

Before starting, ensure your VPS meets the following minimum requirements: * A Linux VPS (Ubuntu 22.04 LTS or Debian 12 recommended). * A user account with sudo privileges. * Docker Engine and Docker Compose V2 installed. * A domain name pointing to your VPS IP address (e.g., git.example.com).


Directory and Permission Setup

Gitea executes inside Docker as a non-root user (default UID 1000, GID 1000). To avoid volume mounting and file permission mismatch issues on the host, create a dedicated directory structure and verify local ownership:

# Create the root project directory
sudo mkdir -p /opt/gitea

# Create directories for Gitea data and PostgreSQL
sudo mkdir -p /opt/gitea/data /opt/gitea/postgres

# Change ownership to UID 1000 to match Gitea container defaults
sudo chown -R 1000:1000 /opt/gitea/data
sudo chown -R 999:999 /opt/gitea/postgres

The Docker Compose Configuration

Create /opt/gitea/docker-compose.yml with the following service definitions. This configuration sets up Gitea alongside a PostgreSQL database, isolates them on a private Docker bridge network, and sets limit restraints on PostgreSQL.

version: '3.8'

networks:
  gitea_net:
    driver: bridge

services:
  db:
    image: postgres:15-alpine
    container_name: gitea_db
    restart: always
    environment:
      - POSTGRES_USER=gitea
      - POSTGRES_PASSWORD=secure_postgres_password_here
      - POSTGRES_DB=gitea
    networks:
      - gitea_net
    volumes:
      - ./postgres:/var/lib/postgresql/data
    shm_size: '256mb'
    deploy:
      resources:
        limits:
          memory: 1gb

  web:
    image: gitea/gitea:1.21.11
    container_name: gitea_web
    restart: always
    depends_on:
      - db
    networks:
      - gitea_net
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "127.0.0.1:3000:3000"
      - "127.0.0.1:2222:22"
    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=secure_postgres_password_here

Key Configuration Directives:

  • Port Binding: The ports 3000 (HTTP) and 22 (SSH) are bound strictly to 127.0.0.1. This blocks direct external access, forcing all web traffic through a reverse proxy and securing the raw HTTP server.
  • User mapping: USER_UID=1000 and USER_GID=1000 ensure files written to the volume map back to user 1000 on the host, preventing root-owned lockouts.

Configuring SSH Passthrough

While mapping port 2222 to the host allows SSH Git operations, it requires remote users to configure custom SSH URLs (e.g., git clone ssh://git@domain:2222/user/repo.git). To enable standard git@domain:user/repo.git links, configure SSH container passthrough on the host.

Step 1: Create the git User on the Host

Create a dedicated git user on your VPS host system matching the container's UID/GID:

sudo groupadd -g 1000 git
sudo useradd -u 1000 -g git -m -s /bin/bash git

Step 2: Set Up Authorized Keys Forwarding

Create a wrapper script on the host to forward incoming SSH commands directly into the Gitea Docker container.

Create /usr/local/bin/gitea-shell on the host:

sudo tee /usr/local/bin/gitea-shell << 'EOF'
#!/bin/sh
ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"
EOF

sudo chmod +x /usr/local/bin/gitea-shell

Next, link Gitea's internal public keys list to the host git user's keys. Add the following symbolic link so keys updated inside Gitea's web UI are instantly recognized by the host:

sudo mkdir -p /home/git/.ssh
sudo ln -s /opt/gitea/data/git/.ssh/authorized_keys /home/git/.ssh/authorized_keys
sudo chown -R git:git /home/git/.ssh

Reverse Proxy Configuration

You must use a reverse proxy to terminate TLS certificates and route traffic to the container. Below are configuration templates for both Nginx and Caddy.

Option A: Nginx with Let's Encrypt

Install Nginx and certbot:

sudo apt update && sudo apt install nginx certbot python3-certbot-nginx -y

Create /etc/nginx/sites-available/gitea with the following configuration:

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

    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 configuration and fetch a Let's Encrypt certificate:

sudo ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d git.example.com

Option B: Caddy (Automatic HTTPS)

If you prefer a simpler alternative with automated certificate rotation, use a Caddyfile:

git.example.com {
    reverse_proxy 127.0.0.1:3000
}

Initial Deployment and Post-Installation

Start the stack using Docker Compose:

cd /opt/gitea
docker compose up -d

Navigate to https://git.example.com in your browser. Gitea will display its initial setup wizard. Set the following options under Gitea Settings:

  • Database Type: PostgreSQL
  • Host: db:5432
  • Database Name: gitea
  • Database Username: gitea
  • Database Password: <your_postgres_password>
  • Server Domain: git.example.com
  • SSH Port: 22 (Ensure this reflects the host port since passthrough is set up)
  • Gitea HTTP Port: 3000
  • Gitea Base URL: https://git.example.com/

Create your administrator account on the setup page, and click Install Gitea.


Backup Strategy

Gitea provides a built-in dump utility to back up the database, repositories, and configurations cleanly. Run the following command to generate a backup archive:

docker exec -u 1000 -it gitea_web gitea dump -c /data/gitea/conf/app.ini

This generates a .zip archive containing: * SQL database dump. * Server configuration (app.ini). * Git repositories. * User uploads and SSH keys.

You can automate this with a cron job to push back up files offsite (e.g., to an S3-compatible storage or another VPS).