Install Gitea on Ubuntu Server
Why Ubuntu for Gitea
Ubuntu Server is the most common platform for self-hosted services. Gitea runs well on it with minimal overhead — you get a full GitHub-like experience with PostgreSQL-backed reliability and native SSH integration for git operations.
Prerequisites
- Ubuntu 22.04 or 24.04 LTS server (fresh install or existing)
- Docker and Docker Compose installed (guide)
- 1 GB RAM minimum (2 GB recommended for active teams)
- 10 GB free disk space (more for large repositories)
- A domain name pointed at your server (optional, for HTTPS)
- Root or sudo access
Install Docker
If Docker is not already installed:
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo usermod -aG docker $USER
Log out and back in for the group change to take effect.
Docker Compose Configuration
Create a directory for Gitea:
mkdir -p ~/gitea && cd ~/gitea
Create docker-compose.yml:
services:
gitea:
image: gitea/gitea:1.25.4
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=gitea_db_password # Change this
- GITEA__server__ROOT_URL=http://localhost:3000/ # Change to your domain
- GITEA__server__SSH_PORT=2222
- GITEA__server__SSH_DOMAIN=localhost # Change to your domain
restart: unless-stopped
volumes:
- gitea_data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000" # Web UI
- "2222:22" # SSH for git operations
depends_on:
db:
condition: service_healthy
networks:
- gitea-net
db:
image: postgres:16-alpine
container_name: gitea-db
restart: unless-stopped
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=gitea_db_password # Must match GITEA__database__PASSWD
- POSTGRES_DB=gitea
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "gitea"]
interval: 10s
timeout: 5s
retries: 5
networks:
- gitea-net
volumes:
gitea_data:
postgres_data:
networks:
gitea-net:
SSH Port Considerations
Port 2222 avoids conflict with the host’s SSH daemon on port 22. Your git clone URLs will look like:
git clone ssh://git@your-server:2222/username/repo.git
If you want clean git@your-server:username/repo.git URLs without the port, you can move the host SSH to a different port and map Gitea to 22. Edit /etc/ssh/sshd_config:
sudo sed -i 's/#Port 22/Port 2222/' /etc/ssh/sshd_config
sudo systemctl restart sshd
Then change the Docker Compose port mapping to "22:22" and set GITEA__server__SSH_PORT=22.
Start Gitea
docker compose up -d
Verify both containers are running:
docker compose ps
UFW Firewall Rules
If UFW is enabled (recommended), open the required ports:
# Web UI
sudo ufw allow 3000/tcp comment 'Gitea Web'
# Git SSH
sudo ufw allow 2222/tcp comment 'Gitea SSH'
# If using a reverse proxy for HTTPS
sudo ufw allow 443/tcp comment 'HTTPS'
# Verify
sudo ufw status
If you moved host SSH to port 2222 and Gitea SSH to 22, adjust accordingly — make sure you allow the new host SSH port before reloading UFW or you will lock yourself out.
First-Time Setup
Open http://your-server-ip:3000 in your browser. Gitea shows a one-time setup page. The database fields are pre-filled from the Docker Compose environment variables. Verify they are correct, then:
- Site Title — name your instance (e.g., “My Gitea”)
- Server Domain — your domain or IP address
- SSH Server Port —
2222(or22if you remapped) - Gitea Base URL —
http://your-domain:3000/orhttps://your-domain/if behind a reverse proxy - Admin Account — create your admin user at the bottom of the page
Click Install Gitea. You will be redirected to the login page.
Git Over SSH Setup
To clone repos over SSH, add your public key to your Gitea account:
- Generate a key pair if you do not have one:
ssh-keygen -t ed25519 -C "[email protected]"
- Copy your public key:
cat ~/.ssh/id_ed25519.pub
-
In Gitea, go to Settings > SSH / GPG Keys > Add Key and paste it.
-
Test the connection:
ssh -T git@your-server -p 2222
You should see: Hi there, username! You've successfully authenticated...
HTTPS via Reverse Proxy
For production, put Gitea behind a reverse proxy with Let’s Encrypt. Update the environment variables first:
- GITEA__server__ROOT_URL=https://git.yourdomain.com/
- GITEA__server__SSH_DOMAIN=git.yourdomain.com
Then configure your reverse proxy to forward HTTPS traffic to localhost:3000. See Reverse Proxy Setup for Nginx Proxy Manager, Traefik, or Caddy configurations.
Remove the 3000:3000 port mapping from Docker Compose if the reverse proxy runs on the same host and connects via Docker network.
systemd Auto-Start
Docker containers with restart: unless-stopped start automatically when Docker starts. Docker itself starts on boot by default on Ubuntu. Verify:
sudo systemctl is-enabled docker
If it returns disabled:
sudo systemctl enable docker
Backup
Back up both the Gitea data volume and PostgreSQL:
#!/bin/bash
# backup-gitea.sh
BACKUP_DIR="/opt/backups/gitea/$(date +%Y-%m-%d)"
mkdir -p "$BACKUP_DIR"
# Database dump
docker exec gitea-db pg_dump -U gitea gitea > "$BACKUP_DIR/gitea-db.sql"
# Gitea data (repos, avatars, attachments)
docker run --rm -v gitea_gitea_data:/data -v "$BACKUP_DIR":/backup alpine \
tar czf /backup/gitea-data.tar.gz /data
echo "Backup complete: $BACKUP_DIR"
Schedule with cron for daily backups. See Backup Strategy for the full 3-2-1 approach.
Troubleshooting
Permission Denied on SSH Clone
Symptom: Permission denied (publickey) when cloning via SSH.
Fix: Verify your SSH key is added to your Gitea account. Check you are connecting to the correct port:
ssh -T git@your-server -p 2222 -v
The verbose flag shows which key is being offered. Ensure the key in ~/.ssh/id_ed25519.pub matches the one in Gitea.
Port 3000 Already in Use
Symptom: Container fails to start with bind: address already in use.
Fix: Another service is using port 3000. Find it:
sudo lsof -i :3000
Change the host port in Docker Compose to something else, e.g., "3001:3000", and update ROOT_URL accordingly.
Database Connection Refused
Symptom: Gitea logs show dial tcp: connect: connection refused for PostgreSQL.
Fix: The database container may not be ready. Check the health status:
docker compose ps
If db shows as unhealthy, check its logs:
docker compose logs db
Common cause: mismatched password between POSTGRES_PASSWORD and GITEA__database__PASSWD.
Web UI Shows 502 After Reverse Proxy Setup
Symptom: Nginx/Caddy returns 502 Bad Gateway.
Fix: The reverse proxy cannot reach Gitea. If both run in Docker, they must share a network. If the proxy runs on the host, Gitea must expose port 3000. Check ROOT_URL matches your actual access URL exactly.
Large Push Rejected
Symptom: RPC failed; HTTP 413 when pushing large files.
Fix: If behind a reverse proxy, increase the client max body size. For Nginx:
client_max_body_size 100M;
For Gitea itself, edit app.ini inside the container or set the environment variable:
- GITEA__server__LFS_MAX_FILE_SIZE=104857600 # 100 MB
Resource Requirements
- RAM: ~150 MB idle, ~300 MB under active use
- CPU: Low (spikes during git operations and CI)
- Disk: 500 MB for the application, plus repository storage
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments