DB-유

Running Gitea on Synology Docker

· synology, docker, gitea

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 is 2222:2222 instead of 2222:22.
  • The web UI works but clone URLs show http://localhost:3000/...: ROOT_URL was not set before the install; edit app.ini under [server] and restart the container.
  • Gitea logs Error 1071: Specified key was too long; max key length is 767 bytes during install: the database was created without utf8mb4 and with an old row format. The command: line in the compose file avoids this; drop and recreate the db folder 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 different USER_UID, so authorized_keys ownership 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.