Why self-host Gitea on a VPS
Gitea uses barely 200 to 300 MB of RAM at idle, making it one of the most efficient Git forges to self-host. On a VPS, you keep full control of your source code: no data is analyzed by a third party, no arbitrary limit on the number of private repositories or collaborators, and no cost that climbs with your team. For an agency or an independent developer in Morocco, a single VPS can host all client projects with permissions partitioned by organization. Gitea natively includes CI/CD compatible with GitHub Actions workflows (Gitea Actions), a package registry and a web editor, which covers almost the entire development cycle with no external dependency.
Concrete benefits of a self-hosted Gitea
- Minimal memory footprint: runs comfortably on a 2 GB RAM VPS even with several dozen users.
- Unlimited private repositories with no per-seat billing, unlike SaaS offerings.
- Gitea Actions built in to run your CI/CD pipelines without an external service.
- Package registry (Docker, npm, Composer, Maven) hosted on the same instance.
- Fine-grained authentication: LDAP, OAuth2, personal access tokens and per-user SSH keys.
- Trivial backup: everything fits in one data volume and a database.
Hardware and software prerequisites
Gitea is very frugal. For a small team (up to 20 users), a VPS with 2 vCPU and 2 GB of RAM is more than enough; count on 4 GB if you enable Gitea Actions with local runners that compile code. Plan for at least 20 to 40 GB of SSD storage depending on the size of your repositories. On the software side: Docker Engine and the Docker Compose plugin installed, a domain name (or a subdomain such as git.yourdomain.com) pointing to the VPS IP via an A record, and port 22 reserved for the server's SSH — Gitea will expose its own SSH on another port to avoid the conflict.
Deploy Gitea with Docker and SSL
Prepare the VPS and Docker
Connect via SSH, update the system then install Docker and the Compose plugin. Create a dedicated directory: mkdir -p /opt/gitea && cd /opt/gitea. Also create a data volume that will survive container updates.
Write the docker-compose.yml
Define two services: gitea (image gitea/gitea:latest) and a postgres:16 database. Mount ./gitea:/data for persistence, set USER_UID/USER_GID to 1000, and map Gitea's SSH to host port 2222: "2222:22". Leave the HTTP port 3000 internal; it will be served by the reverse proxy.
Launch the containers
Run docker compose up -d then docker compose logs -f gitea to follow the initialization. Check that the connection to PostgreSQL succeeds before continuing.
Configure the reverse proxy
With Caddy, a single line is enough: git.yourdomain.com { reverse_proxy localhost:3000 }. Caddy automatically obtains and renews the Let's Encrypt certificate. With Nginx, create a server that proxies to http://127.0.0.1:3000 and use certbot --nginx for SSL.
Finalize the web installation
Open https://git.yourdomain.com, complete the wizard by filling in the HTTPS base URL and the database host (db:5432). Set ROOT_URL correctly, otherwise the clone links will be wrong.
Secure repository SSH
Configure your clients to clone via ssh://[email protected]:2222/..., or add a Host block in ~/.ssh/config to hide the port. Disable public sign-up in the admin if the instance is private.
Enable Gitea Actions right from installation by adding [actions] ENABLED = true to app.ini, then register an act_runner runner in a separate container on the same VPS. Cap its RAM via mem_limit so that a heavy build does not choke Gitea itself. For heavy pipelines (compilation, integration tests), dedicate a second VPS to the runner instead and connect it with the registration token — you keep the forge responsive even during builds.
The official documentation
For advanced configuration and options specific to the tool, refer to the official Gitea documentation. This guide covers going live on a VPS; the vendor's docs remain the reference for fine-tuning, major upgrades and specific use cases.