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_URLis wrong. Fix it in the environment (or indata/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 222for the host in~/.ssh/config. - "Permission denied" errors on start: the
datafolder is owned by a different user thanUSER_UID. Fix it withsudo 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.