Popular
join now

Git Sovereignty: Setting Up Gitea on Synology NAS, Mirroring GitHub, and Mastering Dual Remotes

Tech8hrs agoupdate ICSteve
8 0

# Git Sovereignty: Setting Up Gitea on Synology NAS, Mirroring GitHub, and Mastering Dual Remotes

## 正文

*中文版: [代码资产自托管:群晖 NAS 搭建 Gitea、GitHub 镜像备份与本地双 Remote 实战](https://www.icsteve.com/zh/1552.html)*

In modern software and hardware engineering, Git is the universal fabric of collaboration. Yet, many engineers conflate Git—the distributed version control system—with GitHub, the proprietary cloud platform owned by Microsoft.

Git Sovereignty: Setting Up Gitea on Synology NAS, Mirroring GitHub, and Mastering Dual Remotes

When Linus Torvalds designed Git in 2005, his fundamental architectural principle was radical decentralization: every clone is a fully functional repository with complete historical provenance. There is no inherent "master server" in Git’s protocol. However, modern developer workflows have introduced a single point of failure by centralizing around third-party cloud hosts.

Relying exclusively on a single cloud remote introduces critical risks:

  1. Account lockouts and compliance triggers: Automated risk engines or DMCA takedowns can freeze critical repositories without warning.
  2. Upstream outages & network disconnects: When cloud DNS collapses or local ISPs face fiber cuts, internal development, CI/CD, and deployment pipelines should not grind to a halt.
  3. Intellectual Property & Privacy: Proprietary silicon automation scripts, EDA tooling, private financial ledgers, and personal journal notes belong behind your local firewall.

The solution is not abandoning GitHub—it remains the gold standard for developer visibility, open-source collaboration, and community discovery. The optimal engineering solution is Git Dual-Homing: using GitHub as your collaborative remote while hosting a private, low-latency, resilient Git instance on your local Synology NAS, complete with automated mirroring and dual-remote push capabilities.


Architectural Topology: The Multi-Remote Model

               +-------------------------------------------+
               |        Cloud Remote: GitHub (Public/Team) |
               +-------------------------------------------+
                                   ^     |
                                   |     | [Gitea Pull Mirror]
            [git push origin]      |     v (Scheduled auto-sync)
                               +-----------------------------+
                               | Local Synology NAS: Gitea   |
                               | (Local Intranet Hub: 3000)  |
                               +-----------------------------+
                                        ^
                                        | [git push gitea]
                                        |
                 +--------------------------------------+
                 | Local Developer Workstation (Mac/PC) |
                 | - origin: github.com/user/repo       |
                 | - gitea:  nas-ip:2222/user/repo      |
                 +--------------------------------------+

This topology provides:

  • Zero-Latency LAN Operations: Full read/write performance over 2.5GbE/10GbE local networks.
  • Automated Upstream Sync: Gitea pulls commits, branches, and tags from GitHub on a scheduled interval.
  • Granular Branch Governance: Keep work-in-progress (WIP) and sensitive branches strictly on your NAS, pushing only clean, tagged releases to GitHub.

Part 1: Deploying Gitea on Synology NAS with Container Manager

Why Gitea?

Among self-hosted Git solutions (GitLab, Gogs, Forgejo, Gitea), Gitea is uniquely suited for NAS environments. Written in Go, it runs with exceptional resource efficiency (~80MB to 120MB of RAM) and near-zero idle CPU load, making it ideal for Synology’s x86 or ARM architecture.

Git Sovereignty: Setting Up Gitea on Synology NAS, Mirroring GitHub, and Mastering Dual Remotes

Step 1: Directory Setup

Open File Station on your Synology DSM and navigate to your docker share. Create the following directory hierarchy:

/volume1/docker/gitea/
  └── data/          <-- Repositories, SSH configurations, and SQLite database

Ensure the docker user group has read and write permissions to this directory.

Step 2: Container Manager docker-compose.yml

Open Container Manager in DSM:

  1. Navigate to Project -> Click Create.
  2. Name the project gitea and set the path to /docker/gitea.
  3. Select Create docker-compose.yml and paste the following configuration:
version: "3"

networks:
  gitea_net:
    driver: bridge

services:
  server:
    image: gitea/gitea:latest
    container_name: gitea
    restart: always
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE=sqlite3
      - GITEA__database__PATH=/data/gitea/gitea.db
      - GITEA__server__DOMAIN=192.168.1.100       # Your Synology LAN IP or local hostname
      - GITEA__server__SSH_DOMAIN=192.168.1.100   # Your Synology LAN IP
      - GITEA__server__SSH_PORT=2222              # Custom SSH port avoiding DSM port 22
      - GITEA__server__SSH_LISTEN_PORT=22
      - GITEA__server__ROOT_URL=http://192.168.1.100:3000/
      - GITEA__server__LFS_START_SERVER=true
      - TZ=America/Los_Angeles
    networks:
      - gitea_net
    volumes:
      - /volume1/docker/gitea/data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"   # Gitea Web UI
      - "2222:22"     # Git SSH forwarded from container port 22

Why Port 2222? Synology DSM reserves port 22 for host administration. Mapping container port 22 to external port 2222 allows Git SSH operations without interfering with system management.

Complete the wizard and start the project. Gitea will initialize in seconds.

Step 3: Initial Setup Wizard

  1. Visit http://<SYNOLOGY_IP>:3000 in your browser.
  2. Confirm the prefilled settings (SQLite3, SSH Port 2222, Base URL http://<SYNOLOGY_IP>:3000/).
  3. Scroll down to Administrator Account Settings and configure your primary admin user.
  4. Click Install Gitea.

Part 2: Backing Up (Mirroring) GitHub to Local Gitea

Gitea includes a native Mirror Migration engine. Unlike basic backup scripts that take static snapshots, a mirror continuously synchronizes branches, tags, and commits.

Git Distributed Architecture: Cloud Remote + Local NAS Mirror ☁️ GitHub (Cloud) origin · Primary Upstream 🏠 Synology Gitea (NAS) gitea · Scheduled Pull Mirror Auto Sync Local Workstation (MacBook/PC) Dual Remotes (git push origin / gitea) Multi-push: git remote set-url –add –push

Method A: Web UI Automated Pull Mirror (Recommended)

  1. In the Gitea header, click the + icon and select New Migration.
  2. Select GitHub.
  3. Fill out the migration form:
    • Clone Address: https://github.com/<username>/<repo>.git
    • Authentication: For private repositories, enter a GitHub Personal Access Token (PAT) with repo scope.
    • Mirror Option (CRITICAL): Check the box: This repository will be a mirror.
    • Sync Interval: Select 4h, 8h, or 24h.
  4. Click Migrate Repository.

Gitea will clone the repository and run automated background syncs. Your Synology NAS will maintain an exact historical replica of your upstream GitHub projects.

Method B: CLI Manual Mirror Sync

If you need an immediate local clone before configuring web mirrors:

# 1. Clone a bare mirror from GitHub
git clone --mirror https://github.com/username/my-project.git

# 2. Enter repository directory
cd my-project.git

# 3. Add local Gitea remote
git remote set-url --push origin ssh://git@192.168.1.100:2222/username/my-project.git

# 4. Push all refs and tags to Gitea
git push --mirror

Part 3: Setting Up a 2nd Git Remote on Your Local Workstation

You do not have to choose between GitHub and Gitea on your developer machine. Git natively supports multiple remotes.

Strategy 1: Separate Remotes for Granular Control (Recommended)

1. Inspect Existing Remotes

git remote -v

Output:

origin  git@github.com:steve/my-project.git (fetch)
origin  git@github.com:steve/my-project.git (push)

2. Add Gitea as a Second Remote

git remote add gitea ssh://git@192.168.1.100:2222/steve/my-project.git

Verify your remotes:

gitea   ssh://git@192.168.1.100:2222/steve/my-project.git (fetch)
gitea   ssh://git@192.168.1.100:2222/steve/my-project.git (push)
origin  git@github.com:steve/my-project.git (fetch)
origin  git@github.com:steve/my-project.git (push)

3. Push Selectively

  • Push WIP or private branches only to your NAS:
    git push gitea feature/timing-closure-opt
  • Push public releases to GitHub:
    git push origin main
  • Full backup push to Gitea:
    git push gitea --all && git push gitea --tags

Strategy 2: Dual-Push with a Single Command (origin)

If you want every push to sync to both GitHub and Synology Gitea simultaneously, you can register multiple push URLs under origin:

# 1. Ensure GitHub remains the primary push URL
git remote set-url --add --push origin git@github.com:steve/my-project.git

# 2. Add Gitea as a second push URL under origin
git remote set-url --add --push origin ssh://git@192.168.1.100:2222/steve/my-project.git

Verify the configuration:

origin  git@github.com:steve/my-project.git (fetch)
origin  git@github.com:steve/my-project.git (push)
origin  ssh://git@192.168.1.100:2222/steve/my-project.git (push)

Now, running a single command:

git push origin main

Will sequentially push commits to both GitHub and your local Synology Gitea instance.


Part 4: SSH Client Configuration

To streamline SSH connections on port 2222, configure your local ~/.ssh/config:

Host synology-gitea
    HostName 192.168.1.100
    Port 2222
    User git
    IdentityFile ~/.ssh/id_ed25519

This simplifies your remote command to:

git remote add gitea synology-gitea:steve/my-project.git

Remember to paste your public key (cat ~/.ssh/id_ed25519.pub) into Gitea under User Settings -> SSH / GPG Keys.



Part 5: Disaster Recovery — How to Back Up and Rebuild Gitea

A self-hosted service is only as resilient as its disaster recovery procedure. Containers and application binaries are inherently disposable; your Git repositories, SQLite/PostgreSQL database, user accounts, and configuration secrets (SECRET_KEY, INTERNAL_TOKEN) are your core assets.

Gitea provides an official, atomic backup utility: gitea dump. It packages the database dump, raw repositories, Git LFS data, custom configurations, and server keys into a single compressed .zip archive without stopping the service.

1. Creating an Atomic Backup

Scenario A: Synology Package Center (SynoCommunity native package)

If you installed Gitea via the Synology Package Center (SynoCommunity), Gitea runs under the dedicated system service user sc-gitea. Execute the backup command directly in the Synology SSH terminal:

sudo su -s /bin/sh -c "/var/packages/gitea/target/bin/gitea dump -c /var/packages/gitea/var/conf.ini" sc-gitea

Command Breakdown:

  • sudo su -s /bin/sh -c "..." sc-gitea: Runs the dump sub-command under the sc-gitea service account to ensure all file read permissions are respected and the output archive maintains correct ownership.
  • /var/packages/gitea/target/bin/gitea dump: Invokes Gitea’s built-in CLI backup sub-command.
  • -c /var/packages/gitea/var/conf.ini: Explicitly points to the active Synology package configuration file.

This command generates a timestamped archive (e.g., gitea-dump-1727600000.zip) in the current working directory.

Scenario B: Docker / Container Manager

If running Gitea inside Docker, execute gitea dump inside the container:

docker exec -u 1000 -it gitea /app/gitea/gitea dump -c /data/gitea/conf/app.ini --file /data/gitea-dump-backup.zip

The resulting gitea-dump-backup.zip will immediately be stored on your host at /volume1/docker/gitea/data/gitea-dump-backup.zip.


2. Restoring & Rebuilding Gitea from Scratch

If your NAS storage crashes or you are migrating to a brand-new Synology unit, follow this sequential rebuild protocol:

Step 1: Deploy a Fresh Gitea Instance

Spin up a fresh Gitea instance using Container Manager (using the docker-compose.yml provided in Part 1) or reinstall via Package Center. Once launched, immediately stop the service to avoid database locking during file restoration:

# For Docker:
docker stop gitea

# For Package Center:
sudo synopkg stop gitea

Step 2: Unzip the Dump Archive

Transfer your gitea-dump-*.zip to the server and extract it into a temporary staging folder:

unzip gitea-dump-*.zip -d /tmp/gitea-restore/

The archive contains the following essential structures:

  • repos/: All bare Git repositories.
  • gitea-db.sql: The complete database dump.
  • data/: Attachments, avatars, and Git LFS objects.
  • app.ini: Master server configuration including encryption keys.

Step 3: Restore Data & Database

For a Docker-based deployment:

  1. Restore repositories:
    cp -R /tmp/gitea-restore/repos/* /volume1/docker/gitea/data/git/repositories/
  2. Restore configuration:
    cp /tmp/gitea-restore/app.ini /volume1/docker/gitea/data/gitea/conf/app.ini
  3. Restore database (SQLite):
    sqlite3 /volume1/docker/gitea/data/gitea/gitea.db < /tmp/gitea-restore/gitea-db.sql
  4. Restore data & LFS:
    cp -R /tmp/gitea-restore/data/* /volume1/docker/gitea/data/gitea/

Step 4: Fix Permissions

Incorrect UID/GID permissions will prevent Gitea from reading repositories over SSH or HTTP. Reset ownership to match your deployment:

# Docker environment (matching UID 1000 in compose file):
sudo chown -R 1000:1000 /volume1/docker/gitea/data

# Package Center environment:
sudo chown -R sc-gitea:sc-gitea /var/packages/gitea/var/

Step 5: Start Gitea & Resync Hooks

Start the container or package service:

docker start gitea

Log in as administrator, navigate to Site Administration -> Dashboard -> Operations, and run these two essential maintenance tasks:

  1. Resync pre-receive, update and post-receive hooks of all repositories.
  2. Resync missing SSH keys (rebuilds the .ssh/authorized_keys file).

Your Gitea instance is now 100% recovered with all history, users, and mirrors intact.


Part 5: Disaster Recovery — How to Back Up and Rebuild Gitea

Gitea provides an official atomic backup command gitea dump without taking the service offline.

1. Atomic Backup Command

Scenario A: Synology Package Center (SynoCommunity)

sudo su -s /bin/sh -c "/var/packages/gitea/target/bin/gitea dump -c /var/packages/gitea/var/conf.ini" sc-gitea

Scenario B: Docker / Container Manager

docker exec -u 1000 -it gitea /app/gitea/gitea dump -c /data/gitea/conf/app.ini --file /data/gitea-dump-backup.zip

2. 5-Step Rebuild Protocol

  1. Deploy clean instance & stop immediately (docker stop gitea);
  2. Extract archive (unzip gitea-dump-*.zip -d /tmp/gitea-restore/);
  3. Restore data & DB (copy repos, restore app.ini, import SQL);
  4. Fix ownership (sudo chown -R 1000:1000 /volume1/docker/gitea/data);
  5. Start & resync hooks in Admin dashboard.

Summary Comparison

Dimension Cloud Only (GitHub) Dual-Homed (GitHub + Synology Gitea)
Availability Dependent on external internet & SaaS health 100% LAN uptime at 2.5G/10G network speeds
Data Sovereignty Subject to third-party policy changes Stored on local Btrfs RAID with snapshot capabilities
Backup Cadence Manual exports / API rate limits Automated pull mirror + simultaneous dual push
Branch Governance Binary (entire repository is public or private) Flexible: WIP on local Gitea, clean releases on GitHub

Self-hosting Git on a local NAS alongside GitHub restores the original distributed design of Git. It secures your intellectual property, protects against upstream disruptions, and gives you total sovereignty over your engineering assets.

© Copyright notes

Related posts

No comments

No comments...