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-v1.3.2-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 — v1.3.2
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.