Running Gitea on Synology Docker
Bare repositories on the NAS were fine until a third person joined and started asking where the pull requests were. Once more than two people collaborate you want a web UI, code browsing, issues, and a way for people to add their own SSH keys without bugging me. Gitea is a single Go binary that does all that on modest memory, which suits a NAS. Here's Gitea 1.12 with MariaDB in Docker on DSM 6.2, with Git over SSH on its own port so it doesn't clash with DSM's sshd.
Two free ports are needed, 3000 for HTTP (or a reverse proxy in front) and 2222 for Gitea's SSH, plus the Docker package, SSH access and a docker share. A hostname like git.example.com helps if you want it reachable from outside.
Folders and IDs
sudo mkdir -p /volume1/docker/gitea/data /volume1/docker/gitea/db
sudo synouser --get git 2>/dev/null || sudo synouser --add git 'Change-Me-1' "Gitea service" 0 "" 0
id git
Gitea's image runs its Git processes as a user whose UID and GID you choose with USER_UID/USER_GID. Creating a matching DSM user named git keeps file ownership readable in File Station; note its UID from id git (for example 1030) and use it below.
Compose file
/volume1/docker/gitea/docker-compose.yml:
version: '2.4'
services:
db:
image: mariadb:10.4
container_name: gitea-db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root-secret
MYSQL_DATABASE: gitea
MYSQL_USER: gitea
MYSQL_PASSWORD: gitea-secret
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes:
- /volume1/docker/gitea/db:/var/lib/mysql
gitea:
image: gitea/gitea:1.12
container_name: gitea
restart: unless-stopped
depends_on:
- db
environment:
USER_UID: "1030"
USER_GID: "100"
GITEA__database__DB_TYPE: mysql
GITEA__database__HOST: db:3306
GITEA__database__NAME: gitea
GITEA__database__USER: gitea
GITEA__database__PASSWD: gitea-secret
GITEA__server__DOMAIN: git.example.com
GITEA__server__ROOT_URL: https://git.example.com/
GITEA__server__SSH_DOMAIN: git.example.com
GITEA__server__SSH_PORT: "2222"
GITEA__service__DISABLE_REGISTRATION: "true"
volumes:
- /volume1/docker/gitea/data:/data
- /etc/timezone:/etc/timezone:ro
ports:
- "3000:3000"
- "2222:22"
The GITEA__section__KEY environment variables are written into app.ini on first start (supported since 1.11), which means the compose file is the whole configuration. SSH_PORT is what Gitea shows in clone URLs; the container listens on 22 internally and the NAS publishes it as 2222.
cd /volume1/docker/gitea
sudo docker-compose up -d
sudo docker-compose logs -f gitea
First start
Open http://nas-ip:3000. The install page is prefilled from the environment; check the database fields, set the administrator account at the bottom, and click Install Gitea. The settings land in /volume1/docker/gitea/data/gitea/conf/app.ini. Anything you change later goes either into that file or into compose environment variables followed by docker-compose up -d.
Reverse proxy and firewall
Control Panel → Application Portal → Reverse Proxy → Create: Source HTTPS git.example.com:443, Destination HTTP localhost:3000. Gitea does not need WebSockets. On the router forward 443 to the NAS as usual and 2222 → NAS:2222 for SSH clones. In the DSM firewall allow 2222 from anywhere and keep 3000 LAN-only.
Mail and backups
I set up mail early, since a Git server that can't send a password reset is annoying. For notification mail, add to the gitea service environment and recreate:
GITEA__mailer__ENABLED: "true"
GITEA__mailer__HOST: smtp.example.com:587
GITEA__mailer__FROM: gitea@example.com
GITEA__mailer__USER: gitea@example.com
GITEA__mailer__PASSWD: mail-secret
Backups: Gitea has a built-in dump that produces a zip with the repositories, database and configuration. Task Scheduler, nightly as root:
#!/bin/bash
mkdir -p /volume1/docker/gitea/backup
docker exec -u git gitea sh -c 'cd /tmp && gitea dump -c /data/gitea/conf/app.ini' >/dev/null
docker exec gitea sh -c 'ls -t /tmp/gitea-dump-*.zip | head -n1' | \
xargs -I{} docker cp gitea:{} /volume1/docker/gitea/backup/
docker exec gitea sh -c 'rm -f /tmp/gitea-dump-*.zip'
find /volume1/docker/gitea/backup -name 'gitea-dump-*.zip' -mtime +14 -delete
Hyper Backup then picks up the backup folder along with the rest of the share.
Push something
Create a repository in the web UI, then from a workstation:
git clone ssh://git@git.example.com:2222/jsmith/test.git
cd test && echo hi > a.txt && git add . && git commit -m init && git push
Confirm the SSH clone URL shown by Gitea includes :2222. On the NAS, check the repository landed under /volume1/docker/gitea/data/git/repositories/jsmith/test.git owned by UID 1030. Site Administration → Configuration in the web UI shows the effective app.ini values, which is where to confirm ROOT_URL and the mailer.
Trouble I hit
ssh: connect to host git.example.com port 2222: Connection refused: the router or DSM firewall does not forward 2222, or the compose port mapping is2222:2222instead of2222:22.- The web UI works but clone URLs show
http://localhost:3000/...:ROOT_URLwas not set before the install; editapp.iniunder[server]and restart the container. - Gitea logs
Error 1071: Specified key was too long; max key length is 767 bytesduring install: the database was created without utf8mb4 and with an old row format. Thecommand:line in the compose file avoids this; drop and recreate thedbfolder if the first install already failed. - Pushing over SSH asks for
git's password: the public key was added in Gitea but the container was recreated with a differentUSER_UID, soauthorized_keysownership no longer matches. Keep the UID stable, and run Site Administration → Rewrite '.ssh/authorized_keys' file.
I'd pin the image tag and read the release notes before each upgrade. Gitea moves quickly.