项目自述测试不如原生 tridge 版充分、用户尚少,重要数据需自行验证传输结果;SSH 命令模式(setup 3)下客户端可能需显式加 --protocol=27;SSH daemon 模式(setup 4)要求服务端存在 ~/.config/gokr-rsyncd.toml 配置文件
rsync
gokrazyBSD-3-Clause活跃维护用 Go 实现的 rsync 客户端和服务端,支持双向收发文件,可替代原生 rsync 做上传下载和增量同步。
rsync in Go! implements client and server, which can send or receive files (upload, download, all directions supported)
go install github.com/gokrazy/rsync/cmd/gokr-rsync@latest
gokr-rsync --daemon --gokr.listen=localhost:8730 --gokr.modulemap=man=/usr/share/manREADME 未说明
用 Go 实现的 rsync 客户端与服务端,与原生 rsync 协议兼容,可嵌入程序或自建服务
用 Go 实现的 rsync 客户端和服务端,支持双向收发文件,可替代原生 rsync 做上传下载和增量同步。
核心能力
- gokr-rsync 命令同时充当客户端和服务端,支持双向收发文件
- 支持 daemon 模式与 SSH 两种服务方式,可匿名或鉴权
- 提供 rsynccmd 包,可把 rsync 传输嵌入自己的 Go 程序
- 提供 rsyncd 包,可自行实现 rsync 服务端
- 用 os.Root 与 Linux Landlock 沙箱降低路径穿越等漏洞风险
容易踩的坑
- v0.3.10最新正式版2026-10-25 · 2026-10-25 15:18 UTC
This release contains a number of hardening changes to prevent malicious peers from crashing the server or consuming lots of resources (primarily RAM).
Full Changelog: https://github.com/gokrazy/rsync/compare/v0.3.9...v0.3.10
- v0.3.92026-10-21 · 2026-10-21 06:55 UTC
查看更新说明
What's Changed
- security fix: do not run Main() for SSH connections: https://github.com/gokrazy/rsync/commit/84a521ed34427703bf3eb344346f5acfa1e9c192
- receiver: continue deleting sibling files by @2748109647 in https://github.com/gokrazy/rsync/pull/78
New Contributors
- @2748109647 made their first contribution in https://github.com/gokrazy/rsync/pull/78
Full Changelog: https://github.com/gokrazy/rsync/compare/v0.3.8...v0.3.9
- v0.3.82026-09-23 · 2026-09-23 17:32 UTC
查看更新说明
Full Changelog: https://github.com/gokrazy/rsync/compare/v0.3.7...v0.3.8
- v0.3.72026-09-07 · 2026-09-07 14:46 UTC
查看更新说明
Full Changelog: https://github.com/gokrazy/rsync/compare/v0.3.6...v0.3.7
- v0.3.62026-08-07 · 2026-08-07 14:03 UTC
查看更新说明
Full Changelog: https://github.com/gokrazy/rsync/compare/v0.3.5...v0.3.6
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
gokrazy rsync
gokrazy/rsync is an Rsync program and reusable library implemented in the Go programming language, originally as part of the gokrazy Go appliance platform project. gokrazy/rsync is (wire-)compatible with the original "tridge" Rsync.
Various use-cases are supported:
- The
gokr-rsynccommand implements an rsync client and server, which can send or receive files (all directions supported). - You can set up a public or private rsync server, in daemon mode or via SSH (anonymous or authorized).
- You can embed rsync in your program with the
rsynccmdpackage. - You can implement your own rsync server with the
rsyncdpackage.
Aside from being implemented in Go, a memory-safe programming
language, gokrazy/rsync makes use
of Go’s traversal-resistant file API (os.Root)
and the Linux Landlock Unprivileged Sandboxing to steer
clear of
vulnerabilities. In
server settings, gokrazy/rsync supports mount namespaces and can be further
locked down with systemd’s various hardening options.
This project accepts contributions as time permits to merge them (best effort).
Notable users / use-cases
- NVIDIA/OSMA
- backup of gokrazy Go appliances with gokrazy/rsync
- demo: rsync file transfer over gRPC transport
- Simon Leinen’s presentation: Go for rsync Diversity at RIPE 90 (2025)
How do I know this project won’t eat my data?
This rsync implementation is not as well-tested as the original “tridge” implementation from the Samba project. gokrazy/rsync was started in 2021 and doesn’t have many users yet.
With that warning out of the way, the rsync protocol uses MD4 checksums over file contents, so at least your file contents should never be able to be corrupted.
There is enough other functionality (delta transfers, file metadata, special files like symlinks or devices, directory structures, etc.) in the rsync protocol that provides opportunities for bugs to hide.
I recommend you carefully check that your transfers work, and please do report any issues you run into!
Existing rsync implementation survey
| Language | URL | Note | Max Protocol | Server mode? |
|---|---|---|---|---|
| C | RsyncProject/rsync (formerly WayneD/rsync) | original “tridge” implementation; I found older versions easier to study | 32 | ✔ yes |
| C | kristapsdz/openrsync | OpenBSD, good docs | 27 | ✔ yes |
| Go | gokrazy/rsync | → you are here ← | 27 | ✔ yes 🎉 |
| Go | jbreiding/rsync-go | rsync algorithm | ❌ no | |
| Go | kaiakz/rsync-os | only client/receiver | 27 | ❌ no |
| Go | knight42 | proxy | ❌ no | |
| Go | c4milo/gsync | ❌ no | ||
| Java | APNIC-net/repositoryd | archived | ✔ yes | |
| Java | JohannesBuchner/Jarsync | archived, internet draft RFC “The rsync Network Protocol” | ✔ yes | |
| Java | perlundq/yajsync | ✔ yes | ||
| C++ | gilbertchen/acrosync-library | commercial | ❌ no | |
| Rust | sourcefrog/rsyn | archived, client, “rsyn is rsync with no c” | 27 | ❌ no |
Getting started
To serve the /usr/share/man directory via rsync on localhost:8730, use:
go install github.com/gokrazy/rsync/cmd/gokr-rsync@latest
gokr-rsync --daemon --gokr.listen=localhost:8730 --gokr.modulemap=man=/usr/share/man
You can then copy the contents of the current directory with clients such as
rsync(1):
% rsync -v --archive --port 8730 rsync://localhost/man/ man
receiving file list ... done
created directory man
./
ar/
ar/man1/
[…]
zh_TW/man8/userdel.8.gz
zh_TW/man8/usermod.8.gz
sent 658.973 bytes received 88.012.067 bytes 3.940.935,11 bytes/sec
total size is 84.504.170 speedup is 0,95
…or openrsync(1), shown doing a
differential update:
% openrsync -v --archive --port 8730 rsync://localhost/man/ man
openrsync: warning: connect refused: ::1, localhost
Transfer starting: 40202 files
[…]
zh_TW/man8/userdel.8.gz (732 B, 100.0% downloaded)
zh_TW/man8/usermod.8.gz (1.8 KB, 100.0% downloaded)
Transfer complete: 83.93 MB sent, 643.5 KB read, 80.59 MB file size
Usage / Setup
| setup | encrypted | authenticated | private files? | privileges | protocol version | config required |
|---|---|---|---|---|---|---|
| 1. rsync daemon protocol (TCP port 873) | ❌ no | ⚠ rsync (insecure) | ❌ only world-readable | ✔ dropped + namespace | ✔ negotiated | config required |
| 2. anon SSH (daemon) | ✔ yes | ✔ rsync | ❌ only world-readable | ✔ dropped + namespace | ✔ negotiated | config required |
| 3. SSH (command) | ✔ yes | ✔ SSH | ✔ yes | ⚠ full user | ⚠ assumed | no config |
| 4. SSH (daemon) | ✔ yes | ✔ SSH (+ rsync) | ✔ yes | ⚠ full user | ✔ negotiated | ~/.config/gokr-rsyncd.toml required |
Regarding protocol version “assumed”: the flags to send over the network are
computed before starting SSH and hence the remote rsync process. You might
need to specify --protocol=27 explicitly on the client. Once the connection is
established, both sides do negotiate the protocol, though.
Setup 1: rsync daemon protocol (TCP port 873)
Serving rsync daemon protocol on TCP port 873 is only safe where the network layer ensures trusted communication, e.g. in a local network (LAN), or when using Tailscale or similar. In untrusted networks, attackers can eavesdrop on file transfers and possibly even modify file contents.
Prefer setup 2 instead.
Example:
- Server:
gokr-rsync --daemon --gokr.modulemap=module=/srv/rsync-module - Client:
rsync rsync://webserver/module/path
Setup 2: anon SSH (daemon)
This setup is well suited for serving world-readable files without authentication.
Example:
- Server:
gokr-rsync --daemon --gokr.modulemap=module=/srv/rsync-module --gokr.anonssh_listen=:22873 - Client:
rsync -e ssh rsync://webserver/module/path
Setup 3: SSH (command)
This setup is well suited for interactive one-off transfers or regular backups, and uses SSH for both encryption and authentication.
Note that because gokr-rsync is invoked with user privileges (not root
privileges), it cannot do namespacing
and hence retains more privileges. When serving public data, it is generally
preferable to use setup 2 instead.
Note that rsync(1) assumes the server process understands all flags that it
sends, i.e. is running the same version on client and server, or at least a
compatible-enough version. You can either specify --protocol=27 on the client,
or use setup 4, which negotiates the protocol version, side-stepping possible
compatibility gaps between rsync clients and gokr-rsync.
Example:
- Server will be started via SSH
- Client:
rsync --rsync-path=gokr-rsync webserver:path
Setup 4: SSH (daemon)
This setup is more reliable than setup 3 because the rsync protocol version will
be negotiated between client and server. This setup is slightly inconvenient
because it requires a config file to be present on the server in
~/.config/gokr-rsyncd.toml.
Note that this mode of operation is only implemented by the original “trigde”
rsync, not in openrsync. Apple started shipping openrsync with macOS 15 Sequoia.
For a while, /usr/libexec/rsync/rsync.samba was still available, but on more
recent macOS versions you need to use homebrew or Nix to get tridge rsync.
Example:
- Server will be started via SSH
- Client:
rsync -e ssh --rsync-path=gokr-rsync rsync://webserver/module/path
Limitations
Bandwidth
In my tests, gokr-rsync can easily transfer data at > 6 Gbit/s. The current
bottleneck is the MD4 algorithm itself (not sure whether in the “tridge” rsync
client, or in gokr-rsync). Implementing support for more recent protocol
versions would help here, as these include hash algorithm negotiation with more
recent choices.
Protocol related limitations
- xattrs (including acls) was introduced in rsync protocol 30, so is currently not supported.
Supported environments and privilege dropping
Supported environments:
- systemd (Linux)
- privileged Linux (running as
root, or in a user namespace) - privileged non-Linux
- unprivileged Linux, Mac or Windows
In all environments, the default instructions will take care that:
gokr-rsyncuses Go’s Traversal-resistantos.Rootfile APIs to restrict all file access to the specified paths.- (On privileged Linux only) Only configured rsync modules from the host file
system are mounted (read-only, unless the module is
writable) into a Linux mount namespace forgokr-rsync, to guard against data modification and data exfiltration. - (On Linux only) File system access is restricted using the
Landlock Linux kernel
security module, which works similar to OpenBSD’s
unveil(2)API. - (On privileged environments)
gokr-rsyncdrops privileges to usernobody, to limit the scope of what an attacker can do when exploiting a vulnerability.
Known gaps:
gokr-rsyncdoes not guard against denial of service attacks, i.e. consuming too many resources (connections, bandwidth, CPU, …).- See also Per-IP rate limiting with iptables.
systemd (unprivileged)
We provide a gokr-rsyncd.socket and gokr-rsyncd.service
file for systemd. These
files enables most of systemd’s security features. You can check by running
systemd-analyze security gokr-rsyncd.service, which should result in an
exposure level of “0.2 SAFE” as of systemd 249 (September 2021).
First, configure your server flags by creating a systemd service override file:
systemctl edit gokr-rsyncd.service
In the opened editor, change the file to:
[Service]
ExecStart=
ExecStart=/usr/bin/gokr-rsync --daemon --gokr.modulemap=pwd=/etc/tmpfiles.d
Close the editor and install the service using:
systemctl enable --now gokr-rsyncd.socket
Additional hardening recommendations:
- Restrict which IP addresses are allowed to connect to your rsync server, for example:
- using iptables or nftables on your host system
- using
gokr-rsync’s built-in IP allow/deny mechanism - using systemd’s
IPAddressDenyandIPAddressAllowingokr-rsyncd.socket
- To reduce the impact of Denial Of Service attacks, you can restrict resources with systemd, see Managing Resources.
- To hide system directories not relevant to any rsync module, use systemd’s
TemporaryFileSystem=andBindReadOnlyPaths=directives as described in Use TemporaryFileSystem to hide files or directories from systemd services. Note that you may need to disableProtectSystem=strictdue to a bug.
privileged Linux (including gokrazy.org)
When started as root on Linux, gokr-rsync will create a Linux mount
namespace, mount all configured
rsync modules read-only into the namespace, then change into the namespace using
chroot(2) and drop privileges using
setuid(2).
Tip: you can verify which file system objects the daemon process can see by
using ls -l /proc/$(pidof gokr-rsync)/root/.
Additional hardening recommendations:
- Restrict which IP addresses are allowed to connect to your rsync server, for example:
- using iptables or nftables on your host system
- using
gokr-rsync’s built-in IP allow/deny mechanism
privileged non-Linux (e.g. Mac)
When started as root on non-Linux (e.g. Mac), gokr-rsync will drop
privileges using setuid(2).
unprivileged with write permission (e.g. from a shell)
To prevent accidental misconfiguration, gokr-rsync refuses to start when it
detects that it has write permission in any configured rsync module.