Gitea is a self-hosted Git service that feels like a lean GitHub: repositories, pull requests, issues, a built-in CI (Gitea Actions), and a clean web UI — all from a single Go binary. It's a great fit for teams that want code hosting they fully control without the resource footprint of heavier platforms.
The two things that trip people up when deploying Gitea on a container platform are persistent repository storage and SSH access for git operations. This guide handles both.
What Gitea needs
| Component | Production setup |
|---|---|
| Gitea app | Container app |
| Repository storage | Persistent volume (repos live on disk) |
| Database | Managed PostgreSQL (SQLite only for tiny setups) |
| HTTP access | Web UI + HTTPS git |
| SSH access | Port 22-style access for git@ clones |
Step 1: Provision managed PostgreSQL
While Gitea can use SQLite, a real database is better for any team. On [PandaStack](https://dashboard.pandastack.io), create a managed PostgreSQL. Gitea reads its DB config from environment variables or app.ini.
GITEA__database__DB_TYPE=postgres
GITEA__database__HOST=<managed-host>:5432
GITEA__database__NAME=gitea
GITEA__database__USER=<user>
GITEA__database__PASSWD=<password>
GITEA__database__SSL_MODE=requireGitea's env-var convention is GITEA__
__ (double underscores) mapping to app.ini.Step 2: Persist repositories — mandatory
Git repositories are stored on disk under Gitea's data directory. On an ephemeral container, that means your repos vanish on redeploy without a volume. Attach a persistent volume mounted at /data (the official image's data root).
This volume holds repos, LFS objects, avatars, and the SQLite DB if you used it. It must persist for the life of your Gitea instance.
Step 3: Configure the container
FROM gitea/gitea:1.22
# Web on 3000, SSH on 22 inside the containerCore environment variables:
GITEA__server__DOMAIN=git.example.com
GITEA__server__ROOT_URL=https://git.example.com/
GITEA__server__HTTP_PORT=3000
GITEA__server__SSH_DOMAIN=git.example.com
GITEA__server__SSH_PORT=2222
GITEA__service__DISABLE_REGISTRATION=true
GITEA__security__INSTALL_LOCK=trueROOT_URLmust match your HTTPS domain so clone URLs and links are correct.DISABLE_REGISTRATION=truestops strangers creating accounts (enable invites instead).INSTALL_LOCK=trueskips the web installer once configured.
Step 4: Handle SSH access
This is the trickiest part on container platforms. There are two ways to clone:
- 1HTTPS clones — work out of the box once the web app is exposed with SSL.
https://git.example.com/org/repo.gitwith a personal access token. For many teams this is enough. - 2SSH clones —
git@git.example.com:org/repo.git. This needs a TCP port exposed for SSH, not just HTTP.
For the simplest setup, start with HTTPS clones using access tokens — no extra port wrangling, and tokens are easy to manage. If your team strongly prefers SSH, expose a dedicated TCP port (e.g. 2222) for Gitea's built-in SSH server and set SSH_PORT accordingly so generated clone URLs point users at the right port:
git clone ssh://git@git.example.com:2222/org/repo.gitStep 5: Deploy
- 1Push the repo (or reference
gitea/gitea) to GitHub. - 2Create a container app on PandaStack.
- 3Attach the persistent volume at
/data. - 4Set the DB and server env vars (passwords as secrets).
- 5Expose the web port
3000; expose the SSH TCP port if using SSH clones. - 6Add a custom domain matching
ROOT_URL; SSL is automatic. - 7Link the managed PostgreSQL.
Step 6: First-run and admin
With INSTALL_LOCK=true and env config set, Gitea skips the installer. Create the first admin via the CLI in the running container, or temporarily allow the installer to create it:
gitea admin user create --admin --username root --password '<strong>' --email admin@example.comThen invite your team and disable any open registration.
Step 7: Gitea Actions (optional CI)
Gitea includes a GitHub-Actions-compatible CI. To use it, enable Actions and deploy a separate act_runner that registers with your Gitea instance and executes workflows. This lets you run .gitea/workflows/*.yml pipelines on push — a nice perk of self-hosting.
Operating tips
- Back up both the database and the
/datavolume. Repos live on the volume; metadata in PostgreSQL. You need both for a full restore. - Use Git LFS for large binaries; configure LFS storage (volume or object storage).
- Keep Gitea updated — pin minor versions and read upgrade notes.
- Monitor disk usage on the volume; active teams accumulate repo and LFS data.
References
- [Gitea documentation](https://docs.gitea.com/)
- [Gitea Docker installation](https://docs.gitea.com/installation/install-with-docker)
- [Gitea configuration cheat sheet](https://docs.gitea.com/administration/config-cheat-sheet)
- [Gitea Actions](https://docs.gitea.com/usage/actions/overview)
---
Gitea gives a team full ownership of their code hosting in a tiny footprint — the keys are a persistent volume for repositories and managed PostgreSQL for metadata, both of which PandaStack provides with scheduled backups. Start HTTPS-first, add SSH if you need it, and deploy at [dashboard.pandastack.io](https://dashboard.pandastack.io).