Self-hosted Gitea,
managed from one binary.
Install, upgrade, and configure Gitea and act_runner — declarative config, built-in secret management, systemd units. One verifiable binary, no runtime to babysit.
$ curl -fsSL https://dl.gtcnsl.com/latest/gtcnsl-v0.6.3-linux-amd64 -o /usr/local/bin/gtcnsl && chmod +x /usr/local/bin/gtcnsl
What it does
The whole Gitea lifecycle, declarative and verifiable.
Verified install & upgrade
Pulls Gitea and act_runner from the official mirror, checked against GPG signatures and SHA-256.
Declarative app.ini
Keep desired state in Git. gtcnsl config apply reconciles the server — with a diff and a backup first.
Secret management
Generate, rotate, and store Gitea secrets safely. No hand-edited files, no leaks in shell history.
systemd units
Manages the gitea and gitea-runner units directly — start, stop, status, enable.
TUI and CLI
Interactive TUI by default; a non-interactive CLI for cron and CI pipelines.
Multi-arch
linux amd64, arm64, and armv7. From a VPS to a Raspberry Pi in the closet.
A console, not a script
Launch gtcnsl with no arguments and you get a real terminal UI — services, config drift, and secrets at a glance.
Quickstart
Zero to a running Gitea with CI — three commands.
gtcnsl gitea install --domain git.example.com
Installs Gitea, generates secrets, writes app.ini, and starts the systemd unit.
gtcnsl runner install
Installs act_runner and its gitea-runner unit.
gtcnsl runner register --instance https://git.example.com
Registers the runner with your instance. CI is live.
Declarative by default
Keep app.ini in Git. gtcnsl config apply reconciles the server — with a diff and a backup first.
[server]DOMAIN = git.example.comROOT_URL = https://git.example.com/SSH_PORT = 2222[actions]ENABLED = true[security]INSTALL_LOCK = true
$ gtcnsl config apply~ [server] SSH_PORT 22 → 2222+ [actions] ENABLED = truebackup → /var/backups/gitea/app.ini.2026-05-303 changes applied · gitea restarted
Runs where you run
One binary across the distros and architectures you actually deploy.
Why a binary, not a script
Built for people who treat their server like production.
One static binary
No Python, no Ansible, no runtime to install or version. Drop it on the box and run.
Verifiable
Every download is checked against GPG signatures and SHA-256 before it touches your system.
Idempotent
Declarative state means re-running is safe. Apply the same config twice, get the same server.
Whole lifecycle
Install, upgrade, configure, and run — one tool instead of a folder of fragile shell scripts.
Status
v0.x — early, but already running in production homelabs.
Questions
Only what your declarative config covers. Everything else is left alone, and config apply shows a diff and writes a backup before any change.
Yes. Point it at your current app.ini, review the diff, and apply only what you want. There is no all-or-nothing migration.
For installs and service operations, yes — it manages systemd units. Read-only commands like status and config diff do not.
No. No account, no telemetry, no phone-home. One binary and your server.
GPG signature plus SHA-256 against the official Gitea mirror, every time.