Fully verified57,748

Development

Gitea

Gitea hosts Git repositories, pull requests, issues, wikis, and package registries on your own server. This recipe uses the official image and PostgreSQL, disables open registration, and binds web and SSH to localhost.

Overview

Gitea is an open-source Git service for small teams and personal projects. It combines repositories, code review, issues, projects, wikis, releases, package registries, and built-in CI/CD support without handing code to an external platform.

This recipe runs the pinned official Gitea 1.27.3 image with PostgreSQL 17.11. The web UI and built-in SSH server bind to localhost, and open registration is disabled. Gitea Actions and a runner are intentionally out of scope.

Security and exposure

The full smoke test has passed on amd64 and arm64; backup and restore remain untested in practice. Public web access requires an HTTPS reverse proxy. Only expose SSH after configuring the administrator, keys, and firewall. Repositories, attachments, and configuration live under /data; PostgreSQL stores the database separately.

Update tracking

These are stored results of separate checks, not real-time data. An unknown status means the check has not been performed yet.

New releases

Recipe version compared with the latest known upstream release. A version number, not a reading of what changed.

Current version 1.27.3Sep 1, 2026, 4:15 PM UTC

Critical vulnerabilities

Result of a dedicated Docker image scan, not a Compose configuration check.

Not checkedNot checked

Breaking updates

A new major version is found by comparing version numbers. A compatibility verdict is entered by hand after reading the release notes and the migration steps.

Not checkedNot checked

compose.yaml

Upstream Compose changes relative to the verified recipe.

Upstream Compose is not trackedNot checked

Outdated Docker images

Pinned image tags checked for newer versions.

Not checkedNot checked

From observation to action

Update plan

The recipe already pins the latest known release. The steps below show the evidence retained for that version.

1.27.31.27.3
  1. Open the release evidence

    Open this release on GitHub ↗ The link is evidence to review, not proof of compatibility.

  2. Review the version boundary

    The version numbers do not cross a major compatibility boundary. No compatibility verdict has been recorded.

  3. Prepare image-tag changes

    No image-tag change is currently planned.

  4. Follow the documented migration shape

    Manual steps after the pull. Release-specific migration steps still come from the release notes and installation guide.

  5. Protect the rollback point

    No version change is currently planned. The recipe includes a backup procedure. Restore has not been tested.

  6. Verify the updated recipe

    An exact Fully verified check for this target was recorded on 2026-09-03.

Read the update procedure in the installation guide ↓

Specifications

Security and exposure

Installation levels

The status shows how fully the published recipe meets each level's requirements.

Partial

For home

A minimal setup for a local network or access through a VPN.

  • Single server
  • Local access
  • Minimum components

You still need to add: single server, local access, minimum components.

Partial

For a VPS

A public deployment with protected access and backups.

  • Domain
  • HTTPS via reverse proxy
  • Off-server backup

You still need to add: domain, https via reverse proxy, off-server backup.

Partial

Reliable

A setup designed for predictable operations and observability.

  • Separate database
  • Healthcheck
  • External monitoring
  • CPU and memory limits

You still need to add: external monitoring, cpu and memory limits.

Tailored to your server

Configuration generator

Answer five questions and download a ready-to-run Gitea bundle.

Runs locally
01 Do you have a domain?
02 Which reverse proxy?
03 Server architecture
04 Where should data be stored?

Use an absolute path for a separate disk, such as /srv/gitea.

05 Is VPN access required?

Your bundle is ready

The archive is created in your browser. Your answers are never sent anywhere.

Screenshots

Screenshots have not been added yet.

Quick start

Read the full guide first: it explains external access, backups, and data locations.

Prepare settingscp .env.example .env
Launchdocker compose up -d
Check statusdocker compose ps

Step-by-step guide

1. Check the server

Use Ubuntu 22.04+ or Debian 12+ with Docker Engine and Compose v2.24+. Allocate at least 1 CPU, 512 MB RAM, and 5 GB disk; 1 GB RAM plus space for repositories, packages, and backups is recommended.

docker --version
docker compose version

2. Configure the recipe

mkdir -p ~/services/gitea
cd ~/services/gitea
cp .env.example .env
chmod 600 .env
openssl rand -base64 36

Put the generated value in POSTGRES_PASSWORD, replace git.example.com, and never publish .env. GITEA_HTTP_PORT and GITEA_SSH_PORT select local ports; GITEA_DOMAIN, GITEA_SSH_DOMAIN, and GITEA_ROOT_URL define public addresses; the POSTGRES_* variables configure the database; the volume variables name persistent storage; GITEA_BACKUP_DIR selects backup storage.

3. Start Gitea and create an administrator

docker compose config
docker compose pull
docker compose up -d --wait
curl --fail http://127.0.0.1:3000/api/healthz
read -rsp 'Administrator password: ' GITEA_ADMIN_PASSWORD
docker compose exec gitea gitea admin user create --admin --must-change-password --username admin --email admin@example.com --password "$GITEA_ADMIN_PASSWORD"
unset GITEA_ADMIN_PASSWORD

The password is not stored in shell history, but is briefly passed to the process inside the container; change it immediately in the UI. Open registration is disabled. Gitea persists its data under /data.

VPS deployment

Keep both bindings on 127.0.0.1 and expose web only through HTTPS. Test SSH through ssh -L 2222:127.0.0.1:2222 user@server, then ssh -p 2222 git@localhost. To expose Git over SSH publicly, change only its Compose binding to a specific VPS address such as ${SERVER_IP}:${GITEA_SSH_PORT}:22, document SERVER_IP in .env, and allow that TCP port through the firewall. Keep port 3000 local.

Trusted LAN access

Prefer a VPN or SSH tunnel. If the proxy runs on another LAN host, bind web to a specific private server address and allow only the proxy through the firewall. Do not use 0.0.0.0 without network restrictions.

Domain and HTTPS

Replace the domain in .env and one file under proxy/. Caddy obtains a certificate, Nginx expects Certbot files, and Traefik uses the letsencrypt resolver. The proxy must preserve the URI and forward Host, X-Forwarded-Proto, and the client address. A containerized Traefik needs a reachable host gateway instead of 127.0.0.1.

Backup

chmod +x backup.sh restore.sh
./backup.sh

The script stops Gitea, runs a native pg_dump, archives the complete data volume, and starts the service again. Stopping is required: the repositories on disk and the database rows describing them are consistent with each other only while nothing writes. The archive lands in GITEA_BACKUP_DIR. Encrypt it because it contains private code, keys, and configuration. Keep an off-server copy and test restores regularly.

Restore

Restore irreversibly replaces the data volume and database. The script takes an emergency copy of the current state before replacing it. Use the same Gitea version, check .env, then:

./restore.sh ./backups/gitea-YYYYMMDDTHHMMSSZ.tar
docker compose ps
curl --fail http://127.0.0.1:3000/api/healthz

The script finishes with gitea admin regenerate hooks: hook scripts embed absolute paths and the binary version, so they must be rewritten after the data directory is replaced. The procedure has not passed a practical restore test; test it on a separate server first.

Update

Back up first and read the release notes and upgrade guide. The image is pinned in compose.yaml: replace 1.27.3 with a reviewed exact version, update the exact PostgreSQL tag if needed, then run docker compose pull && docker compose up -d --wait. Do not switch between rootful and rootless images because their data layouts are incompatible.

Rollback

Never run an old image over a migrated database. Restore the previous exact Gitea and PostgreSQL tags, then restore the entire pre-update directory using the procedure above. Rolling back migrations without a synchronized file and database backup is unsafe.

Stop and remove

docker compose down preserves data. After verifying an external backup, remove all data with:

docker compose down
docker volume rm gitea-data gitea-database
rm -rf ~/services/gitea

Sources: official Docker installation, backup and restore, reverse proxies, and upgrades.

Troubleshooting

Gitea does not become healthy

docker compose ps
docker compose logs --tail=200 gitea database
docker inspect --format '{{json .State.Health}}' "$(docker compose ps -q gitea)"

Check the database password, free disk space, and volume access. /api/healthz must return HTTP 200.

Permission denied under /data

The official rootful container uses the git user with UID/GID 1000 for persistent data. Do not change USER_UID or USER_GID without migrating ownership. Run chown -R 1000:1000 before using a bind mount.

Clone URLs show the wrong domain or port

Check GITEA_ROOT_URL, GITEA_DOMAIN, GITEA_SSH_DOMAIN, and GITEA_SSH_PORT, then run docker compose up -d --force-recreate.

SSH is not reachable externally

This is the safe default: SSH binds to localhost. Test through a tunnel first. For public access, follow the VPS section, change only the SSH binding, inspect the firewall, and diagnose with ssh -vvv -p 2222 git@git.example.com.

The reverse proxy returns 502

Check curl http://127.0.0.1:3000/api/healthz, the upstream address, and whether the proxy can reach host localhost. A containerized proxy has a different localhost namespace.

Push fails after a restore

Inspect the logs and regenerate Git hooks:

docker compose exec gitea gitea admin regenerate hooks
docker compose exec gitea gitea doctor check --all

Official sources

Latest release: 2026-08-29 · GitHub Stars: 57,748 · metadata checked Sep 1, 2026, 4:15 PM UTC

Disclaimer

Fossary is an independent informational catalog and is not affiliated with the developers of the listed applications. We collect information from public sources and verify published recipes, but we do not develop, distribute, or control these applications.

A listing or validation status is not a requirement, endorsement, or personal recommendation to use an application. You decide whether it is suitable and use it at your own risk. We do not warrant an application's security, availability, or fitness for purpose and, to the extent permitted by law, are not liable for resulting loss or damage. Review its license, security settings, data processing, and backup procedures before installation.