Forgejo
A private git host in one container, behind Caddy for the web and on its own port for git over SSH.
Names and addresses are placeholders. The list says what each one stands for.
What it does here
Forgejo holds the repositories and runs Actions. The rest of the box exists to keep it running, reachable and backed up.
Canonical setup
One container from Forgejo's own registry, pinned to the current stable major, with its data in a volume. Finish the first-run screen in a browser: keep SQLite for a personal instance, create the admin account there, and turn off open registration.
Upstream: Installation with Docker.
In this build
- HTTP bound to 127.0.0.1:3000Only Caddy can reach it, as
git.dev.tailnet.example. - ROOT_URL on the private nameClone links and redirects use
https://git.dev.tailnet.example/. - git over SSH on host port 2222The host's own sshd keeps port 22 for administration.
- Data on /srv/data/forgejo
- Mail through the shared relayMailer settings are on the msmtp card.
services:
forgejo:
image: codeberg.org/forgejo/forgejo:11
container_name: forgejo
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
- FORGEJO__server__DOMAIN=git.dev.tailnet.example
- FORGEJO__server__ROOT_URL=https://git.dev.tailnet.example/
- FORGEJO__server__SSH_PORT=2222
volumes:
- /srv/data/forgejo:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
networks: [forgejo]
ports:
- "127.0.0.1:3000:3000"
- "2222:22"
networks:
forgejo:mkdir -p /srv/stacks/forgejo && cd /srv/stacks/forgejo
docker compose config
docker compose up -dBefore Caddy is up, reach the first-run screen through an SSH tunnel: ssh -L 3000:localhost:3000 youruser@devbox, then open http://localhost:3000.
Host git.dev.tailnet.example
Port 2222
User git
IdentityFile ~/.ssh/id_ed25519Seams
Where this meets the rest of the build. Each one leads with what you will actually see.
SymptomPermission denied
Port 22 is the host's sshd, which has no git user, so the short git@host:owner/repo form fails even with a valid key. Use the ssh:// form with the port, ssh://git@git.dev.tailnet.example:2222/OWNER/REPO.git, or the host entry above so the short form uses 2222.
Symptomdid not find expected key
nano's autoindent mangles pasted YAML. Write compose files from the shell with a heredoc (cat > docker-compose.yml <<'EOF'), use spaces not tabs, and run docker compose config before up.
Verify
docker compose ps # forgejo is Up
curl -sI http://127.0.0.1:3000 | head -1 # HTTP 200
ssh -T -p 2222 git@git.dev.tailnet.example # greets you by usernameThen push to a test repository over SSH.
- 17 Oct 2026First written.