Skip to content
gtcnsl
EN RU
Static Go binary · zero runtime deps

Self-hosted Gitea,
managed from one binary.

Install, upgrade, and configure Gitea and the Runner — HTTPS, declarative config, backup, and self-update. One verifiable binary, no runtime to babysit.

Read the docs → ✓Verified with SHA-256
$ curl -fsSL https://dl.gtcnsl.com/latest/gtcnsl-v2.1.1-linux-amd64 -o /usr/local/bin/gtcnsl && chmod +x /usr/local/bin/gtcnsl
✓ SHA-256 checksums verified on download.
// 02

What it does

The whole Gitea lifecycle, declarative and verifiable.

gpg 01

Verified install & upgrade

Pulls Gitea from the official mirror with GPG and SHA-256 verification, and the Runner with SHA-256; detects an existing install and upgrades it safely in place.

tls 02

HTTPS profiles & adopt

Direct HTTPS via built-in ACME or your own certificate, with automatic rollback. gitea adopt brings a hand-rolled install under management without moving data.

ini 03

Declarative app.ini

Keep desired state in Git. gtcnsl config apply reconciles the server — with a diff and a backup first. config get/set/toggle for one-off changes.

key 04

Secret management

Generate, rotate, and store Gitea secrets safely — including a guarded SECRET_KEY rotation that re-encrypts every affected row instead of orphaning it.

sys 05

Backup, restore & self-update

Snapshots Gitea binary and config for restore, manages the gitea and gitea-runner systemd units, and keeps gtcnsl itself current with self-update — every step rolls back on failure.

i/o 06

TUI and CLI

Interactive TUI by default; a non-interactive CLI for cron and CI pipelines — the same static binary for linux amd64, arm64, and armv7.

// 03

A console, not a script

Launch gtcnsl with no arguments and you get a real terminal UI — services, config presence, and secrets at a glance.

gtcnsl — v2.1.1
gtcnsl — Main menu
SERVICES
giteaactive · 1.27.0
gitea-runneractive · 2.2.0
CONFIG
app.ini/etc/gitea/app.ini (present)
secrets4/4 managed
ACTIONS
> Gitea — install / upgrade
Runner — install / register / upgrade
Config — apply / get / set / toggle
Secrets — generate / check / rotate
Doctor — host prereqs / installed-Gitea / installed-runner
Self-update — check / apply / rollback
↑ move up • ↓ move down • enter select • r refresh status • esc back • ? toggle help • q quit
// 04

Quickstart

Zero to a running Gitea with CI — three commands.

1
$ gtcnsl gitea install --yes

Installs Gitea, generates secrets, writes app.ini, deploys the systemd unit, and starts it — rolled back automatically if the health check fails.

2
$ gtcnsl runner install --executor=docker --yes

Installs the Runner and its gitea-runner unit with the Docker executor. It stays stopped until you register it.

3
$ gtcnsl runner register --instance https://git.example.com --token <fresh-token> --yes

Registers the runner with your instance and starts it. Grab a token from Site Admin, Runners, Create new runner.

// 05

Declarative by default

Keep app.ini as a template in Git. gtcnsl config apply renders it with --var overrides, shows a diff, backs up the old file, then restarts Gitea with a health check.

app.ini.tmpl
[server]
PROTOCOL = http
HTTP_PORT = 3000
SSH_PORT = ${SSH_PORT}
DOMAIN = localhost
ROOT_URL = http://localhost:3000/
APP_DATA_PATH = /var/lib/gitea/data
[actions]
ENABLED = ${ACTIONS_ENABLED}
gtcnsl config apply
$ gtcnsl config apply --template /root/app.ini.tmpl --var SSH_PORT=2222 --var ACTIONS_ENABLED=true --yes
==> render template
template /root/app.ini.tmpl (681 bytes), 2 variable(s)
done in 0s
==> parse current
done in 0s
==> diff
2 change(s):
[actions] ENABLED: "true" (added)
[server] SSH_PORT: "22" → "2222" (changed)
done in 0s
==> apply
backup written to /etc/gitea/app.ini.bak
done in 9ms
==> restart + health check
gitea.service restarted
Gitea is responding again
done in 1.019s
applied 2 change(s) to /etc/gitea/app.ini
// 06

Runs where you run

One binary across the distros and architectures you actually deploy.

Debian
13
Ubuntu
24.04 LTS
Rocky
9
linux/amd64 linux/arm64 linux/armv7
From a cloud VPS to a Raspberry Pi in the closet.
// 07

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

Gitea downloads are checked against GPG signatures and SHA-256; the Runner and gtcnsl itself are checked by SHA-256 — every time, before anything 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.

// 08

Status

v1.x — the CLI is stable and SemVer-versioned since v1.0.

Shipped v1.2
Install, upgrade & adopt Gitea and the Runner
HTTPS profiles — built-in ACME or your own certificate
Declarative app.ini with diff + backup
Secret generation, rotation & safe re-encryption
systemd units, backup/restore & self-update
TUI and non-interactive CLI
Exploring later
Multi-host management over SSH
app.ini database migration (SQLite to PostgreSQL/MySQL)
Incremental repository backups
Alpine / OpenRC support
More supported distributions
// 09

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. gtcnsl gitea adopt brings a hand-rolled install under management without moving data (dry-run by default), then config apply reconciles app.ini against your template with a diff and a backup first.

For installs and service operations, yes — it manages systemd units. Read-only commands like doctor and config get do not.

No. No account, no telemetry, no phone-home. One binary and your server.

Gitea binaries are checked against their GPG signature and SHA-256; the Runner and gtcnsl self-update are checked by SHA-256 — every download, every time.