HiddenGit private Git · Tor v3 · SSH

First deployment, end to end

This tutorial starts with an empty checkout and ends with authenticated SSH over both loopback and the generated Tor v3 onion endpoint. It deliberately does not enable HTTP, native git://, or LFS.

1. Inspect the release before running it

git status --short --branch
./run.sh version
git show --no-patch --decorate

For a release installation, verify that the checked-out tag is v$(cat VERSION). The release’s SBOM/provenance artifacts are produced by CI and should be reviewed alongside the source when supply-chain assurance matters.

2. Initialize private local configuration

./run.sh init
stat -c '%a %n' .env data data/soft-serve data/tor backups

Expected .env mode is 600; state directories are private. init refuses to overwrite an existing .env.

3. Add the bootstrap administrator

Create or select an Ed25519 key on the operator machine:

ssh-keygen -t ed25519 -f ~/.ssh/hiddengit-admin
cat ~/.ssh/hiddengit-admin.pub

Copy only the public-key line into .env:

SOFT_SERVE_INITIAL_ADMIN_KEYS="ssh-ed25519 AAAA... operator@example"

The field is bootstrap-only. It is required while the first database is being created; it is not a private-key store and must never contain the private key.

4. Review operator intent

The normal deployment fields are deliberately short:

SOFT_SERVE_NAME=HiddenGit
ONION_PUBLIC_PORT=8002
LOCAL_SSH_PORT=23231
HOST_BIND_ADDRESS=127.0.0.1
SOFT_SERVE_SSH_PUBLIC_URL=

LOCAL_SSH_PORT controls only the loopback-facing host port. It does not change Soft Serve’s internal listener. ONION_PUBLIC_PORT controls only the virtual onion port. Both map to internal SSH 23231.

5. Validate before state creation

./run.sh config check
./run.sh config
./run.sh doctor

config check is Docker-free and fails on duplicate, unknown, stale, malformed, or release-pin-drifted configuration. config additionally renders Compose. doctor evaluates operational posture such as file modes, loopback publication, container users, backup freshness, and Docker isolation.

6. Start and wait for the whole path

./run.sh up

up does more than docker compose up:

schema check
    ↓
first-boot key check
    ↓
runtime ownership check/migration for empty state
    ↓
Soft Serve :23231 healthy
    ↓
Tor bootstrap = 100% + onion hostname exists
    ↓
authenticated onion SSH probe

If any required stage fails, the command exits non-zero rather than declaring the service ready early.

7. Connect locally

ssh -i ~/.ssh/hiddengit-admin -p 23231 admin@127.0.0.1

If LOCAL_SSH_PORT was changed, use that host port instead.

8. Connect through Tor

./run.sh status

Assume it reports example.onion and port 8002. With oniux:

Host hiddengit
  HostName example.onion
  User admin
  Port 8002
  ProxyCommand oniux nc %h %p
  IdentityFile ~/.ssh/hiddengit-admin
  IdentitiesOnly yes
  StrictHostKeyChecking accept-new

Then:

ssh hiddengit
git clone ssh://hiddengit/OWNER/REPOSITORY.git

The first connection establishes an SSH host-key trust decision. Verify the host key through an independent channel when your threat model requires it.

9. Create the first backup before real work accumulates

Generate an age identity, move it offline, configure only the public recipient, then perform a stopped-state backup. Follow the backup and recovery tutorial before treating the service as recoverable.

Completion checklist