Overview
Gitea is a lightweight self-hosted Git service — repositories, pull requests, issues and a built-in package registry. This template deploys one Gitea server (the rootless image) on a persistent volume, a bundled PostgreSQL database from the PostgreSQL template, a public HTTPS endpoint serving the web UI, Git-over-HTTPS and the package registry, and optional Git-over-SSH. The site administrator’s login and Gitea’s three long-lived signing keys are not template values. They come from one dictionary secret you create before installing, so they never pass through Helm and never land in the release. The bundled database’s credentials are internal plumbing: the template builds that secret for you from plain values.What Gets Created
Prerequisites
One secret must exist before you install. Secrets are org-level, so no GVC flag is involved.Create the auth secret
admin* keys create the first site-admin account on first boot; the other three are Gitea’s signing keys:gitea.auth.secretName to this name. Read it back later with cpln secret reveal GITEA_AUTH_SECRET_NAME -o yaml — a bare cpln secret reveal prints only a summary table, not the values.postgres.credentials.*. Pick a database password at install time (see Installation). Database backups are optional and need a bucket plus, for AWS or GCP, a Control Plane cloud account — see Backing Up.
Installation
Install the chart from the marketplace registry, pointing it at the auth secret and replacing the published database-password placeholder:postgres.config.credentialsSecretName to a name unique to that release — secret names are org-wide, and a second release left on the default is refused at install (see Troubleshooting).
Or follow the instructions for your preferred method:
UI
CLI
Terraform
Pulumi
Configuration
Each block below is the shipped default for that part ofvalues.yaml.
Image and Resources
maxCpu to minCpu may not exceed 4:1. Raising maxCpu without raising minCpu can cross that limit and is rejected when the workload is applied.Storage
Gitea
gitea.auth.secretName names the prerequisite dictionary secret from Prerequisites. Its admin* keys are consumed once, at first boot: editing the secret later does not change the existing administrator account — see Rotating the Admin Password.
Public Access
git clone and git push from laptops and CI are the point of the service, self-registration is closed by default, and the admin login is a credential you created rather than a published default. Set publicAccess.enabled: false to keep Gitea inside the GVC and reach the UI through cpln port-forward (see Connecting). A change to publicAccess can take several minutes to take effect — re-test before concluding it did not apply.
Git-over-SSH
*.cpln.app canonical endpoint. With ssh.enabled: true that endpoint serves Git-over-SSH on ssh.externalPort instead of HTTPS, so the public web UI and Git-over-HTTPS are no longer reachable at it. SSH is therefore off by default, and Git-over-HTTPS supports full clone, push and pull, so most installs never need it.
When SSH is enabled, Gitea’s built-in SSH server listens on container port 2222 behind a direct TCP load balancer on ssh.externalPort, and the SSH user is git. Clone URLs advertise ssh.domain, or the web host when it is empty — with the default of 22 the repository page shows the familiar form:
ssh.domain to a custom domain that points at the SSH endpoint if you want clean git@ URLs that do not change with the endpoint.
ssh.enabled: false, Gitea’s REST API still reports a placeholder ssh://git@localhost:2222/... clone URL on repository objects. It is cosmetic — the web UI’s clone widget offers only the HTTPS URL — and affects only scripts that read ssh_url from the API.Internal Access
Bundled Database
The database is internal plumbing: it serves Gitea only, is unreachable from outside the GVC, and no human types its password into a client — so the credentials stay plain values and the template writes them into the dictionary secret named bypostgres.config.credentialsSecretName. The password is used as-is, so change it before installing.
postgres.credentials.* only when its volume is first initialized. Changing them afterwards rewrites the secret but not the running database’s password — rotate inside PostgreSQL first, as described in the PostgreSQL template, then update the value and force a redeployment of RELEASE_NAME-gitea so it reconnects with the new password.Database Backup
Every knob of the PostgreSQL template is available underpostgres.*, including its scheduled backup. It is off by default; enabling it adds one cron workload that runs pg_dumpall and uploads a gzip-compressed dump to your bucket. The job authenticates with the chart-created database credentials secret, and the database identity picks up the bucket-scoped policy or cloud account automatically.
postgres.backup. A database dump alone is not a full Gitea backup: repositories, LFS objects and attachments live on the Gitea volume. See Backing Up.
Connecting
http://localhost:3000 in place of the canonical endpoint:
First Run
There is no web install wizard — the chart locks installation and creates the site administrator from your auth secret on first boot.- Open the canonical endpoint (or
http://localhost:3000through the tunnel) and sign in withadminUsernameandadminPasswordfrom the auth secret. - Self-registration is closed by default (
gitea.disableRegistration: true). Create accounts under Site Administration → Identity & Access → User Accounts, or setgitea.disableRegistration: falseand upgrade the release to allow open sign-up. - Create a repository and push to it over HTTPS. The clone widget gives the URL; authenticate with your Gitea username and password, or generate an access token under Settings → Applications.
Operations
Backing Up
The chart schedules no backups of its own. A complete Gitea backup has two halves: the database (users, issues, pull requests, settings) and the Gitea volume (repositories, LFS objects, attachments, packages). Database. Enable the bundled PostgreSQL’s scheduledpg_dumpall with postgres.backup.enabled: true as described under Database Backup, or take a one-off dump through the database container. The dump is base64-encoded in transit because cpln workload exec is not binary-safe:
gitea dump bundles the database and the volume contents into one archive. The commands below are built from the image’s paths (GITEA_APP_INI is set in the container; the container user owns /var/lib/gitea) but have not been exercised against this template — rehearse on a throwaway release first. Write the archive, then stream it out base64-encoded:
secretKey is the only way to read the 2FA secrets, access tokens and mirror credentials in any database dump.
Restoring a Backup
Restore into a fresh release that points at the same auth secret the backup was taken under — a differentsecretKey makes the restored tokens and 2FA secrets unreadable. Then:
-
Database. For a scheduled
pg_dumpallobject, follow the PostgreSQL template’s Restoring a Backup againstRELEASE_NAME-postgres.GVC_NAME.cpln.local. For apg_dumparchive taken as above, load it through the database container (--stdinis required): -
Gitea volume. Either restore the volume set snapshot taken earlier (
cpln volumeset snapshot restore— check--help; not exercised here), or unpack agitea dumparchive and copy itsrepos/contents to/var/lib/gitea/git/repositoriesand itsdata/contents to/var/lib/gitea/datain the Gitea container, as described in the upstream backup and restore guide. -
Regenerate hooks and restart. After repositories are in place, run the upstream post-restore step and restart Gitea so it re-reads the database:
Rotating the Admin Password
The bootstrap script creates the administrator once; on later starts the account already exists and the secret’sadminPassword is not re-applied. Change the password in the Gitea UI: sign in as the administrator and use Settings → Account.
Updating adminPassword in the secret afterwards keeps your records consistent but has no effect on the live account. Never change secretKey or jwtSecret — the first makes every stored 2FA secret, access token and mirror credential permanently unreadable, the second invalidates every issued OAuth2 token.
Upgrading from 1.0.0
Template version 1.0.0 took the admin login and all three security values as plain Helm values and shipped published defaults for every one of them. Version 1.1.0 moved them into the prerequisite auth secret and rejects each old key at render with a message naming its replacement, so the upgrade fails before anything is applied and the running release is left untouched. There are no compatibility fallbacks.Create the auth secret from your current values
gitea.admin.* and gitea.security.* values your 1.0.0 release was installed with.Remove the six old keys from your values
gitea.admin.* and gitea.security.*, and set gitea.auth.secretName to the secret’s name.Apply the 1.1.0 database rename too
Upgrading from 1.1.0
Version 1.2.0 adopted the PostgreSQL template 3.4.1 as its bundled database. That template no longer takes credentials as values, and Gitea absorbed the change rather than passing it on: there is no new prerequisite, only a rename. The database keeps the credentials it was initialized with, so carry the same three values over under the new keys.postgres.config.credentialsSecretName (default my-gitea-db-credentials) and hands only the name to the database. Secret names are org-wide, so give each Gitea release its own.
Scaling and Availability
- Gitea is pinned to one replica. Do not raise it — each replica would get its own repository volume, and there is no shared storage between them.
- The first
cpln helm upgradeafter an install can restart the bundled database, so expect Gitea to be briefly unreachable during it. Treat every upgrade as a short planned outage. - A node failure reschedules the server and reattaches the same volume. The exposure is minutes of downtime, not data loss. The Gitea volume set takes one final snapshot when it is deleted, kept for seven days; it is not snapshotted on a schedule, so use the backup steps above for point-in-time copies.
Troubleshooting
Workload never becomes ready and cpln logs returns nothing
Workload never becomes ready and cpln logs returns nothing
RELEASE_NAME-gitea stays not ready indefinitely, and cpln logs '{gvc="GVC_NAME", workload="RELEASE_NAME-gitea"}' --limit 50 --since 10m returns zero lines.Cause: gitea.auth.secretName names a secret that does not exist, so the container is never started. The reason is visible only in status.versions[].message:cpln workload force-redeployment RELEASE_NAME-gitea --gvc GVC_NAME.Gitea restarts at startup complaining about the JWT secret
Gitea restarts at startup complaining about the JWT secret
cpln logs shows Gitea failing while decoding the OAuth2 JWT_SECRET.Cause: the jwtSecret key in your auth secret is not base64url of exactly 32 bytes — a hex string or passphrase was used.Fix: this key can be changed safely before any OAuth2 token has been issued. Regenerate it with openssl rand -base64 32 | tr '+/' '-_' | tr -d '=', update the secret, and run cpln workload force-redeployment RELEASE_NAME-gitea --gvc GVC_NAME — a running replica does not pick up a changed secret on its own.Upgrade fails with 'gitea.admin.username was removed in 1.1.0'
Upgrade fails with 'gitea.admin.username was removed in 1.1.0'
cpln helm upgrade stops before touching any resource:gitea.admin.password, gitea.admin.email, gitea.security.secretKey, gitea.security.internalToken and gitea.security.jwtSecret each produce the same kind of message under their own name.Cause: your values still carry keys that were removed in 1.1.0.Fix: follow Upgrading from 1.0.0. Your running release is unaffected until the upgrade succeeds.Upgrade fails with 'config.username was REMOVED in postgres 3.4.0'
Upgrade fails with 'config.username was REMOVED in postgres 3.4.0'
cpln helm upgrade to 1.2.0 stops at render with a message from the bundled PostgreSQL chart:postgres.config.username, postgres.config.password or postgres.config.database, which moved to postgres.credentials.* in 1.2.0.Fix: rename the three keys as in Upgrading from 1.1.0. Do not create a database secret yourself — this template creates it.Second release refused: 'cannot be updated because it is being managed by a different release'
Second release refused: 'cannot be updated because it is being managed by a different release'
postgres.config.credentialsSecretName (default my-gitea-db-credentials), and secret names are org-wide. The first release owns it; nothing is shared, overwritten or deleted.Fix: install the second release with --set postgres.config.credentialsSecretName=UNIQUE_NAME.Admin password changed in the secret but the old one still works
Admin password changed in the secret but the old one still works
adminPassword in the auth secret, but Gitea still accepts the previous password.Cause: the bootstrap script creates the administrator only once; afterwards the password lives in the database, not the secret.Fix: change it in the Gitea UI — see Rotating the Admin Password.Enabled SSH and the public web UI stopped responding
Enabled SSH and the public web UI stopped responding
ssh.enabled: true, HTTPS requests to the *.cpln.app endpoint no longer reach Gitea, while git clone over SSH works.Cause: by design — the single canonical endpoint now serves SSH instead of HTTPS. See Git-over-SSH.Fix: serve the web UI through a custom domain, reach it through cpln port-forward RELEASE_NAME-gitea 3000:3000 --gvc GVC_NAME, or set ssh.enabled: false again to get the public web UI back. Allow several minutes for the change to take effect.Important Notes
- Create the auth secret before installing. A reference to a secret that does not exist wedges the workload with no log output; see Prerequisites for the one command that shows the reason.
- Never rotate
secretKeyorjwtSecretafter install. The first makes stored 2FA secrets, tokens and mirror credentials permanently unreadable; the second invalidates issued OAuth2 tokens. jwtSecretmust be base64url of exactly 32 bytes — use the command in Prerequisites.- Change
postgres.credentials.passwordbefore installing. The shippedchange-me-gitea-dbis a published placeholder used as-is. - Give each Gitea release its own
postgres.config.credentialsSecretName. Secret names are org-wide; a second release on the default name is refused at install. - Public SSH and the public web UI cannot share the canonical endpoint — SSH is off by default. See Git-over-SSH.
- Do not scale past one replica. Replicas would each get a separate repository volume.
- Editing the auth secret after first boot does not change the administrator account. Change the password in Gitea — see Rotating the Admin Password.
cpln helm uninstalldeletes both volume sets — repositories and database alike. Your auth secret is yours and is left alone.