# 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.

## Key facts

| Fact | Value |
|---|---|
| App | Gitea (https://appsgit.com/apps/gitea) |
| Difficulty | beginner |
| Time | about 15 minutes |
| Requirements | 1 vCPU / 1 GB RAM; Docker + Docker Compose v2; A domain name (recommended for clone URLs) |
| Last updated | 2026-10-06 |

## 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](https://docs.docker.com/engine/install/ubuntu/). Create a folder and note your user and group IDs:

```bash
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`:

```yaml
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:

```bash
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

```bash
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](https://caddyserver.com/docs/):

```caddyfile
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:

```bash
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:

```bash
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.

## FAQ

### 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.

Prefer not to do it yourself? [appsgit installation help](https://appsgit.com/services/install) installs it on your server for a fixed quote.

---

Canonical page: https://appsgit.com/guides/gitea
Source: appsgit (https://appsgit.com), the app store for github. Data from the GitHub API, refreshed nightly.
Machine access: JSON API https://appsgit.com/api/v1/apps (OpenAPI: https://appsgit.com/openapi.json), MCP server https://mcp.appsgit.com/mcp, full index https://appsgit.com/llms-full.txt.
