Back to Blog
Tutorial10 min read2026-07-01

How to Deploy a Gitea Self-Hosted Git Server

Gitea is a lightweight, self-hosted Git service with a GitHub-like UI. This guide deploys Gitea with persistent storage, managed PostgreSQL, and working SSH for git operations.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

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

ComponentProduction setup
Gitea appContainer app
Repository storagePersistent volume (repos live on disk)
DatabaseManaged PostgreSQL (SQLite only for tiny setups)
HTTP accessWeb UI + HTTPS git
SSH accessPort 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=require

Gitea'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 container

Core 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=true
  • ROOT_URL must match your HTTPS domain so clone URLs and links are correct.
  • DISABLE_REGISTRATION=true stops strangers creating accounts (enable invites instead).
  • INSTALL_LOCK=true skips the web installer once configured.

Step 4: Handle SSH access

This is the trickiest part on container platforms. There are two ways to clone:

  1. 1HTTPS clones — work out of the box once the web app is exposed with SSL. https://git.example.com/org/repo.git with a personal access token. For many teams this is enough.
  2. 2SSH clonesgit@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.git

Step 5: Deploy

  1. 1Push the repo (or reference gitea/gitea) to GitHub.
  2. 2Create a container app on PandaStack.
  3. 3Attach the persistent volume at /data.
  4. 4Set the DB and server env vars (passwords as secrets).
  5. 5Expose the web port 3000; expose the SSH TCP port if using SSH clones.
  6. 6Add a custom domain matching ROOT_URL; SSL is automatic.
  7. 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.com

Then 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 /data volume. 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).

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also