Skip to content
appsgit

Deploy guide

How to self-host Gitea with Docker Compose

Run your own Git server with Gitea, Docker Compose and Postgres: SSH on port 222, the first-run installer, HTTPS reverse proxy, backups and safe upgrades.

  • Updated
  • Beginner
  • About 15 minutes

You will need

  • 1 vCPU / 1 GB RAM
  • Docker + Docker Compose v2
  • A domain name (recommended for clone URLs)

What is Gitea?

Gitea is a lightweight, self-hosted Git service with repositories, pull requests, code review, issues, wikis, a package registry and built-in CI through Gitea Actions. It is written in Go and open source under the MIT license, so it runs on anything from a Raspberry Pi to a large server. If you have used GitHub, the interface will feel familiar.

Requirements

  • A Linux server with 1 vCPU and 1 GB of RAM for a small team.
  • Docker Engine and Docker Compose v2.
  • A domain name, so clone URLs stay stable.

Step 1: Prepare the server

This guide assumes Ubuntu 24.04 with Docker installed. If you need Docker, follow the Docker Engine install guide. Create a folder and note your user and group IDs:

mkdir -p ~/gitea && cd ~/gitea
id -u && id -g

Step 2: Create the Docker Compose file

This setup runs Gitea with Postgres. Save it as docker-compose.yml:

services:
  gitea:
    image: gitea/gitea:28.0
    container_name: gitea
    restart: unless-stopped
    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: ${POSTGRES_PASSWORD}
      GITEA__server__DOMAIN: git.example.com
      GITEA__server__ROOT_URL: https://git.example.com/
      GITEA__server__SSH_DOMAIN: git.example.com
      GITEA__server__SSH_PORT: 222
      GITEA__service__DISABLE_REGISTRATION: "true"
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: gitea
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: gitea
    volumes:
      - ./postgres:/var/lib/postgresql/data

Create .env next to it:

POSTGRES_PASSWORD=CHANGE_ME

Generate the password with openssl rand -hex 32. Set USER_UID and USER_GID to your IDs from Step 1. Any setting from Gitea's app.ini can be passed as an environment variable with the GITEA__section__KEY pattern, which keeps configuration in one place. DISABLE_REGISTRATION stops strangers from signing up; you create the admin in the installer and invite everyone else. The 28.0 tag receives patch releases within the 28.0 line.

Step 3: Start and open the app

docker compose up -d

Open http://YOUR_SERVER_IP:3000. The first-run installer appears with database settings already filled in from the environment. Check that the base URL is https://git.example.com/, expand "Administrator Account Settings", and create the admin user with a strong password. Click "Install Gitea". After a few seconds you are signed in and can create your first repository.

Clone over SSH with git clone ssh://git@git.example.com:222/youruser/repo.git after adding your public key under Settings, SSH / GPG Keys.

Step 4: Put it behind HTTPS

With Caddy:

git.example.com {
    request_body {
        max_size 512MB
    }
    reverse_proxy 127.0.0.1:3000
}

The body size limit matters for large pushes over HTTPS and for package uploads. SSH traffic does not go through the proxy: keep port 222 open in your firewall. After HTTPS works, change the web mapping to "127.0.0.1:3000:3000" so Gitea is only reachable through Caddy.

Backups and upgrades

Gitea includes a dump command that packs repositories, attachments, configuration and a database dump into one zip:

docker compose exec -u git gitea gitea dump -c /data/gitea/conf/app.ini --file /data/gitea-dump.zip

Copy ./data/gitea-dump.zip off-site. Alternatively, back up the data folder plus a pg_dump of the database.

To upgrade, change the image tag when a new minor or major version is out, read the changelog, then run:

docker compose pull && docker compose up -d

Gitea migrates the database automatically. Do not downgrade after a migration has run.

Troubleshooting

  • Clone URLs show localhost:3000: ROOT_URL is wrong. Fix it in the environment (or in data/gitea/conf/app.ini) and restart.
  • SSH asks for a password: you are connecting to the host's SSH on port 22. Use port 222, or add Port 222 for the host in ~/.ssh/config.
  • "Permission denied" errors on start: the data folder is owned by a different user than USER_UID. Fix it with sudo chown -R 1000:1000 data.
  • Large pushes fail with HTTP 413: raise the reverse proxy's body size limit.

Next steps

Enable two-factor authentication, register an act_runner to run Gitea Actions, set up repository mirroring from GitHub, and connect an SMTP server for notifications.

Spotted something out of date? Tell us and we will update the guide.

FAQ

Gitea questions

Still curious? Email info@appsgit.com.

What port does Gitea use?

Gitea serves its web UI on port 3000 and runs an SSH server on port 22 inside the container. This guide maps SSH to host port 222 so it does not clash with the server's own SSH daemon.

Is Gitea free?

Yes. Gitea is free and open source under the MIT license. The company behind it also sells Gitea Enterprise and a hosted cloud, but the self-hosted community edition has no user or repository limits.

Gitea vs Forgejo?

Forgejo is a community fork of Gitea created in 2022 and hosted under the non-profit Codeberg e.V. The two share most features and look alike; Gitea is backed by a company that also sells an enterprise edition, while Forgejo emphasises community governance and federation.

Gitea vs GitLab?

Gitea is a single lightweight binary that runs comfortably on 1 GB of RAM, while self-hosted GitLab needs 4 GB or more. GitLab has a broader built-in DevOps suite; Gitea covers code hosting, pull requests, packages and Actions.

Does Gitea support CI/CD?

Yes. Gitea Actions is built in and largely compatible with GitHub Actions workflow syntax. You run jobs by registering one or more act_runner instances.