Rsync Server 3.5.1 on AWS User Guide
Overview
This guide covers launching and using the Rsync Server 3.5.1 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg SFTP and file server listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
rsync is the standard tool for fast file synchronisation, mirroring and backup: its delta transfer algorithm sends only the parts of files that changed, so repeated syncs of large trees take a fraction of the time and bandwidth of a full copy. This image runs rsync in daemon mode (rsyncd) on TCP port 873, with one module, cloudimg, that your servers and workstations can push backups to and pull files from.
- A password unique to your instance. First boot creates a random 32 character password for the module user
cloudimgand writes it to/root/rsync-credentials.txt. No password is baked into the image, and the daemon cannot start until first boot has created one. - No anonymous access, nothing listed. Every transfer must log in. An anonymous client that asks the server for its module list gets an empty list.
- Every transfer in a jail. Each transfer is locked (chrooted) into
/srv/rsync/cloudimgon a dedicated 20 GiB EBS data volume and runs as the unprivilegedrsyncdaccount. Paths like../../etc/passwdand symbolic links that point outside the module cannot reach the rest of the system, and device files are refused. - Closed until first boot, and fail closed. First boot creates the password, starts the daemon, proves a full round trip and every refusal, and checks that the password did not leak into a log. If anything fails, the daemon is stopped again and the password files are destroyed.
- Hardened service. The daemon runs in a systemd sandbox that can write only to
/srv/rsync, keeps only the five capabilities it needs, and is blocked from the instance metadata service. The AMI requires IMDSv2. - Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
Important: the rsync daemon protocol is not encrypted. The password check is a challenge-response, so the password itself never crosses the network. File names and file contents on TCP 873, however, travel in cleartext. Allow TCP 873 only from the addresses of the machines that sync with the server. For anything sensitive, or over the internet, keep 873 closed and tunnel the daemon through SSH (Step 9) or use rsync over SSH.
What's on the image
- rsync 3.5.1, built by cloudimg from the upstream source, not installed from apt. Ubuntu 24.04's rsync package (3.2.7-1ubuntu1.5) does not include the fixes from the rsync 3.5.0 security release (33 CVEs published on 13 August 2026, for example CVE-2026-70456, an out of bounds heap write, and CVE-2026-70464, an unauthenticated denial of service). The image builds the upstream 3.5.1 release from
https://download.samba.org/pub/rsync/src/rsync-3.5.1.tar.gz. Before anything was compiled, the tarball's SHA-256 checksum and its OpenPGP signature by Andrew Tridgell's release key (fingerprint9FEF 112D CE19 A0DC 7E88 2CB8 1BB2 4997 A853 5F6F) were both verified. The compiler was removed again afterwards. - Updates: because rsync is built from source,
apt upgradeand unattended-upgrades do not update rsync. Ubuntu's rsync package is removed and pinned so that apt can never install it over the upstream build. The operating system and every other package still update through apt. When upstream releases an rsync security fix, cloudimg publishes a new image version on this listing; update by launching the new version and moving/srv/rsyncacross (Step 12), or rebuild rsync yourself from the steps in Step 12. Track upstream at https://download.samba.org/pub/rsync/ and https://github.com/RsyncProject/rsync/releases (this image: version 3.5.1). ubuntu-standardremoved. Ubuntu'subuntu-standardmetapackage is the only package on the image that depends on Ubuntu's rsync package, so it was removed together with it. Every package it had pulled in (cron, logrotate, man-db, wget, nano and the rest) was first marked as manually installed and is still installed; the list is in/usr/local/share/doc/rsync/ubuntu-standard-deps.txt(Step 12). Because of the rsync pin,apt install ubuntu-standardis refused, since it would bring Ubuntu's rsync back; install any of its individual packages as usual.- Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The rsync tools are in
/usr/local/sbin(Step 8).
Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
- A security group that allows TCP 22 for SSH administration and, only if your clients connect to the daemon directly, TCP 873 from your clients' addresses only. With the SSH tunnel (Step 9), port 22 is all you need.
- An rsync client on the machines that sync with the server: rsync ships with almost every Linux distribution and with macOS (as
openrsync); on Windows use WSL.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Rsync Server 3.5.1 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large (rsync needs little CPU; size for your transfer volume), your key pair and a security group as above. The AMI carries two volumes: the 8 GiB root volume and a 20 GiB data volume for /srv/rsync. You can make the data volume larger at launch; first boot grows the file system to fill it.
With the AWS CLI (replace the values in angle brackets; the second mapping sets the data volume size):
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--block-device-mappings 'DeviceName=/dev/sdf,Ebs={VolumeSize=200,VolumeType=gp3}' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=rsync-server}]'
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| Rsync Server 3.5.1 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the service
First boot creates the password, starts the daemon and proves a round trip before it finishes (usually under a minute):
systemctl is-active rsync rsync-prepare rsync-firstboot
sudo test -f /var/lib/cloudimg/rsync-firstboot.done && echo FIRSTBOOT_DONE
All three units are active and the first boot marker is present:
active
active
active
FIRSTBOOT_DONE
Only SSH and the rsync daemon listen on public addresses, and the daemon is the upstream 3.5.1 build:
sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0' | sort
command -v rsync; rsync --version | sed -n 1p
0.0.0.0:22 users:(("sshd",...))
0.0.0.0:873 users:(("rsync",...))
[::]:22 users:(("sshd",...))
[::]:873 users:(("rsync",...))
/usr/local/bin/rsync
rsync version 3.5.1 protocol version 33
Step 4: Get your user and password
sudo grep -vE '^(#|$)' /root/rsync-credentials.txt
The file is readable by root only:
RSYNC_HOST=ec2-<public-ip-dashed>.compute-1.amazonaws.com
RSYNC_PORT=873
RSYNC_USER=cloudimg
RSYNC_PASSWORD=<RSYNC_PASSWORD>
RSYNC_MODULE=cloudimg
RSYNC_URL=rsync://cloudimg@ec2-<public-ip-dashed>.compute-1.amazonaws.com/cloudimg/
RSYNC_MODULE_PATH=/srv/rsync/cloudimg
RSYNC_HOST is the instance's public DNS name from EC2 instance metadata (the public or private IP address when the subnet has no public DNS names). It is the name to use from your clients.
Step 5: Sync from your own machine
Store the password in a file only you can read (rsync refuses a password file that others can read), then push a directory to the server and pull it back. rsync reads the password from the file, so it never appears on a command line or in your shell history:
read -rs PW && printf '%s\n' "$PW" > ~/.rsync-cloudimg.pw && chmod 600 ~/.rsync-cloudimg.pw; unset PW
rsync -av --password-file=$HOME/.rsync-cloudimg.pw ./projects/ rsync://cloudimg@<RSYNC_HOST>/cloudimg/projects/
rsync -av --password-file=$HOME/.rsync-cloudimg.pw rsync://cloudimg@<RSYNC_HOST>/cloudimg/projects/ ./restore/
Add --delete to make the copy on the server an exact mirror (files you deleted locally are deleted on the server too). To schedule a nightly backup, put the push command in a cron job or systemd timer on the client.
Step 6: Push and pull from the instance
This pushes a file, lists the module, pulls the file back and mirrors a deletion, all through the daemon on the instance's own private address. The password is read from a temporary file that only root can read:
sudo bash -c '
F=/root/rsync-credentials.txt
U=$(sed -n "s/^RSYNC_USER=//p" $F); M=$(sed -n "s/^RSYNC_MODULE=//p" $F)
PWF=$(mktemp /run/rsync-pw.XXXXXX); sed -n "s/^RSYNC_PASSWORD=//p" $F > $PWF
IP=$(hostname -I | cut -d" " -f1)
mkdir -p /run/demo && echo "hello from cloudimg" > /run/demo/report.txt
rsync -a --password-file=$PWF /run/demo/ "rsync://$U@$IP/$M/demo/" && echo "push -> ok"
echo "list -> $(rsync --password-file=$PWF "rsync://$U@$IP/$M/demo/" | awk "{print \$NF}" | tr "\n" " ")"
rm -f /run/demo/report.txt; rsync -a --password-file=$PWF "rsync://$U@$IP/$M/demo/report.txt" /run/demo/ && echo "pull -> $(cat /run/demo/report.txt)"
rm -f /run/demo/report.txt; rsync -a --delete --password-file=$PWF /run/demo/ "rsync://$U@$IP/$M/demo/" && echo "delete -> $(rsync --password-file=$PWF "rsync://$U@$IP/$M/demo/" | awk "{print \$NF}" | tr "\n" " ")"
rm -rf /run/demo $PWF /srv/rsync/cloudimg/demo
'
push -> ok
list -> . report.txt
pull -> hello from cloudimg
delete -> .
Pushed files land in /srv/rsync/cloudimg, owned by the unprivileged rsyncd account. To place files there over SSH, copy them in and give them to that account (sudo chown -R rsyncd:rsyncd /srv/rsync/cloudimg/<path>).
Step 7: Run the built in check
The image ships an end to end check you can run at any time; first boot runs it too. It reads the credentials file itself and drives the daemon through the instance's private address:
sudo rsyncd-verify.sh
ok anonymous module listing shows no module (rc 0)
ok anonymous access refused (auth failed, rc 5)
ok user 'anonymous' refused (auth failed, rc 5)
ok wrong password refused (auth failed, rc 5)
ok push cloudimg-verify-<pid>/data.bin (256 KiB)
ok module listing (authenticated) shows the upload
ok pull byte-identical
ok file stored in /srv/rsync/cloudimg owned by rsyncd
ok pull ../../etc/passwd refused (rc 23)
ok pull /etc/shadow (absolute) refused (rc 23)
ok push to ../../ stays inside the module
ok symlink to /etc/shadow cannot be followed out of the module (rc 23)
ok device file not created
ok --write-devices refused (rc 4)
ok live transfer runs as rsyncd (<process counts>)
ok the only root process in rsync.service is the listener (pid <pid>)
ok delete over rsync (--delete)
ok test directory gone from /srv/rsync/cloudimg
RSYNCD_ROUNDTRIP_OK target <private-ip>
It takes about half a minute and leaves the module as it found it.
Step 8: Security checks and the password
An anonymous client sees no modules and cannot log in:
IP=$(hostname -I | cut -d" " -f1); echo "listing: [$(rsync rsync://$IP/)]"
(setsid -w rsync "rsync://$IP/cloudimg/" </dev/null 2>&1 || true) | grep -o '@ERROR.*'
listing: []
@ERROR: auth failed on module cloudimg
The configuration jails every transfer, maps it to the rsyncd account, hides the module and refuses device files:
grep -vE '^[[:space:]]*(#|$)' /etc/rsyncd.conf
pid file = /run/rsyncd/rsyncd.pid
lock file = /run/rsyncd/rsyncd.lock
port = 873
use chroot = yes
numeric ids = yes
uid = rsyncd
gid = rsyncd
max connections = 10
timeout = 600
reverse lookup = no
forward lookup = no
proxy protocol = no
syslog facility = daemon
syslog tag = rsyncd
transfer logging = yes
refuse options = devices specials copy-devices write-devices
[cloudimg]
comment = cloudimg rsync module (per-instance password, chrooted)
path = /srv/rsync/cloudimg
read only = no
write only = no
list = no
auth users = cloudimg
secrets file = /etc/rsyncd.secrets
strict modes = yes
The rsync daemon's challenge-response needs the password on the server, so it is kept in /etc/rsyncd.secrets, readable by root only, beside the credentials file:
sudo stat -c '%a %U:%G %n' /etc/rsyncd.conf /etc/rsyncd.secrets /root/rsync-credentials.txt /srv/rsync /srv/rsync/cloudimg
644 root:root /etc/rsyncd.conf
600 root:root /etc/rsyncd.secrets
600 root:root /root/rsync-credentials.txt
755 root:root /srv/rsync
750 rsyncd:rsyncd /srv/rsync/cloudimg
The daemon runs the upstream build in a sandbox that can write only to the data volume, with five capabilities, and cannot reach the instance metadata service:
systemctl show rsync -p ExecStart -p ProtectSystem -p ReadWritePaths -p NoNewPrivileges -p IPAddressDeny -p CapabilityBoundingSet | cut -c1-120
ExecStart={ path=/usr/local/bin/rsync ; argv[]=/usr/local/bin/rsync --daemon --no-detach --config=/etc/rsyncd.conf ; ign
IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32
CapabilityBoundingSet=cap_dac_read_search cap_setgid cap_setuid cap_net_bind_service cap_sys_chroot
ReadWritePaths=/srv/rsync
ProtectSystem=strict
NoNewPrivileges=yes
No per instance password reached a log, the journal, shell history, backups, the data volume or any file in /etc other than the secrets file:
sudo rsyncd-secret-leak-check.sh
LEAKCHECK_OK no per-instance password in the journal, auth.log, syslog, cloud-init, shell history, MOTD, /var/backups, /etc (outside the 0600 secrets file), /srv/rsync or /tmp
The daemon logs the address each client really connected from (never a DNS name or a header the client sends), including refused logins:
sudo journalctl -u rsync --no-pager -o cat | grep -E '^connect from|allowed access|auth failed' | tail -n 3
connect from UNDETERMINED (<client-ip>)
rsync allowed access on module cloudimg from UNDETERMINED (<client-ip>)
auth failed on module cloudimg from UNDETERMINED (<client-ip>) for <user>: <reason>
New password. rsyncd-passwd generates a new 32 character password (shown once) or reads one you choose from standard input, and updates /etc/rsyncd.secrets and /root/rsync-credentials.txt. The daemon reads the secrets file for every new connection, so no restart is needed:
sudo rsyncd-passwd
read -rs PW && printf '%s\n' "$PW" | sudo rsyncd-passwd --password-stdin; unset PW
More users or modules. Add a user:password line to /etc/rsyncd.secrets and the user to the module's auth users (comma separated), or add another [name] block with its own path under /srv/rsync (create the directory owned by rsyncd:rsyncd, mode 0750). Every module must keep auth users and secrets file. To make a module append only (clients cannot delete), add delete to its refuse options. To filter clients inside the daemon as well as in the security group, add hosts allow = <your-cidr> under the module. Changes apply to the next connection.
Step 9: Encrypt the transfer with an SSH tunnel
Because the daemon protocol is cleartext, the safest setup keeps TCP 873 closed in the security group and reaches the daemon through SSH. The per instance password still protects the module, and everything travels inside the SSH connection. On your client:
ssh -i <your-key.pem> -N -L 8873:127.0.0.1:873 ubuntu@<RSYNC_HOST> &
rsync -av --password-file=$HOME/.rsync-cloudimg.pw ./projects/ rsync://cloudimg@127.0.0.1:8873/cloudimg/projects/
Alternatively, use rsync over SSH directly as the ubuntu user (no daemon involved). To write into the module directory, run the remote side with sudo:
rsync -av -e "ssh -i <your-key.pem>" --rsync-path="sudo rsync" ./projects/ ubuntu@<RSYNC_HOST>:/srv/rsync/cloudimg/projects/
If clients must connect to TCP 873 directly, allow it only from their addresses in the security group, and from inside your VPC wherever possible.
Step 10: Limits
The daemon serves at most 10 connections at a time (max connections) and drops a connection that is idle for 10 minutes (timeout = 600). Raise them in /etc/rsyncd.conf for many simultaneous clients; the change applies to the next connection.
Step 11: The data volume
/srv/rsync is its own EBS volume, mounted by file system UUID with nodev,nosuid,noexec, so synced files can never be run as programs:
findmnt -no SOURCE,FSTYPE,OPTIONS /srv/rsync
df -h --output=size,used,avail,target /srv/rsync
/dev/nvme1n1 ext4 rw,nosuid,nodev,noexec,relatime
Size Used Avail Mounted on
20G 28K 19G /srv/rsync
To grow it, increase the volume's size in the EC2 console (Volumes > Modify volume), wait until the modification reaches the optimizing state, then grow the file system online (the next boot does it too):
sudo rsyncd-prepare
Back it up with EBS snapshots or AWS Backup; a snapshot of the data volume holds every synced file.
Step 12: Updates
The operating system updates through apt, and unattended security upgrades are on. rsync itself is the source build described in the overview, so apt does not touch it, and Ubuntu's rsync package cannot be installed over it. The version and where it came from:
rsync --version | sed -n 1p
cat /usr/local/share/doc/rsync/SOURCE.txt
apt-cache policy rsync | sed -n 1,3p
rsync version 3.5.1 protocol version 33
This rsync 3.5.1 was built by cloudimg from the upstream release tarball https://download.samba.org/pub/rsync/src/rsync-3.5.1.tar.gz, whose SHA-256 checksum c55f9c9dc10fb8bec397b399a0fdded53cc9a2d8e30891bb0d63724d25c37bef and OpenPGP signature by Andrew Tridgell's release key 9FEF112DCE19A0DC7E882CB81BB24997A8535F6F (signed 2026-09-21) were both verified before the build, configured with: --prefix=/usr/local --with-rsyncd-conf=/etc/rsyncd.conf --disable-md2man --disable-idn.
It replaces Ubuntu's rsync package (3.2.7-1ubuntu1.5, which lacks the rsync 3.5.0 security fixes); that package is removed and pinned so apt can never reinstall it, which also means apt and unattended-upgrades do NOT update rsync. cloudimg publishes a new image version for every upstream rsync security release (upstream releases and announcements: https://download.samba.org/pub/rsync/ and https://github.com/RsyncProject/rsync/releases); update by launching the new image version, or rebuild from the steps in the user guide.
rsync is free software under the GNU General Public License version 3 or later with an OpenSSL/xxhash linking exception; the licence text is in /usr/local/share/doc/rsync/COPYING and the release notes in /usr/local/share/doc/rsync/NEWS.md.
rsync:
Installed: (none)
Candidate: (none)
ubuntu-standard, the only package that depended on Ubuntu's rsync, was removed with it. Everything it had installed was kept as manually installed and is listed in /usr/local/share/doc/rsync/ubuntu-standard-deps.txt; apt refuses to reinstall the metapackage because of the rsync pin:
grep -vc '^#' /usr/local/share/doc/rsync/ubuntu-standard-deps.txt
apt-get -s install ubuntu-standard >/dev/null 2>&1 || echo "apt refuses ubuntu-standard (it needs Ubuntu's rsync, which is pinned out)"
50
apt refuses ubuntu-standard (it needs Ubuntu's rsync, which is pinned out)
When an rsync release fixes a security issue, cloudimg adds a new image version to this listing. To move to it:
- Launch the new version next to the old instance.
- Stop the daemon on the old instance (
sudo systemctl stop rsync), take a snapshot of its data volume, and create a volume from that snapshot in the new instance's Availability Zone. - On the new instance stop the daemon, attach the volume, and copy the module directory into
/srv/rsync(keeping thersyncd:rsyncdowner), or mount the volume in place of the new one by its UUID in/etc/fstab. Copy any users you added to/etc/rsyncd.secrets(mode 0600) and start the daemon.
Rebuild rsync yourself. To apply a newer upstream release on a running instance, build it the same way the image did, on a temporary directory in /run: download rsync-<version>.tar.gz and its .asc from https://download.samba.org/pub/rsync/src/, verify the signature with gpg --verify against Andrew Tridgell's key (9FEF112DCE19A0DC7E882CB81BB24997A8535F6F), install the build tools (sudo apt-get install gcc make libssl-dev libxxhash-dev libzstd-dev liblz4-dev libpopt-dev libacl1-dev libattr1-dev), run ./configure --prefix=/usr/local --with-rsyncd-conf=/etc/rsyncd.conf --disable-md2man --disable-idn && make, copy the new rsync binary over /usr/local/bin/rsync, run sudo systemctl restart rsync, and remove the build tools again.
Step 13: Server components
| Component | Version | Path |
|---|---|---|
| rsync (daemon and client) | 3.5.1 (upstream source build, protocol 33) | /usr/local/bin/rsync (/usr/bin/rsync links to it) |
| OpenSSL, xxhash, zstd, lz4, popt, libacl | Ubuntu 24.04, updated by apt | system libraries |
| Ubuntu | 24.04 LTS |
| Path | Purpose |
|---|---|
/etc/rsyncd.conf |
Daemon configuration (re-read for every connection) |
/etc/rsyncd.secrets |
Module users and passwords (mode 0600) |
/srv/rsync/cloudimg |
The cloudimg module on the data volume |
/root/rsync-credentials.txt |
Host, user, password and module (mode 0600) |
/usr/local/share/doc/rsync/ |
Licence, release notes and SOURCE.txt |
/etc/apt/preferences.d/cloudimg-no-distro-rsync |
Keeps Ubuntu's rsync package (and so ubuntu-standard) from being installed |
/usr/local/share/doc/rsync/ubuntu-standard-deps.txt |
The packages ubuntu-standard had pulled in, all kept installed |
/usr/local/sbin/rsyncd-* |
Password, check, health check, leak check and volume tools |
Logs go to the journal: journalctl -u rsync.
Troubleshooting
@ERROR: auth failed on module cloudimg. Wrong user or password, or the client sent no password. Usersync://cloudimg@<host>/cloudimg/and--password-file(Step 5). The journal shows the reason (journalctl -u rsync).ERROR: password file must not be other-accessible. Runchmod 600on your password file.- The connection times out. TCP 873 is not open from your address in the security group (or a network ACL or corporate firewall blocks it). Use the SSH tunnel (Step 9) if you prefer to keep 873 closed.
@ERROR: max connections (10) reached. Too many simultaneous clients; raisemax connections(Step 10).skipping non-regular file. Device and special files are refused on purpose.- Nothing answers after launch. Check
systemctl status rsync-firstbootandjournalctl -u rsync-firstboot. Until first boot completes, the daemon is deliberately closed.
Security recommendations
- Allow TCP 873 only from the addresses that sync with the server, or keep it closed and use the SSH tunnel; allow port 22 only from your administrators.
- Remember that data on TCP 873 is not encrypted (Step 9).
- Give each system its own user, keep password files at mode 0600, and change the password with
sudo rsyncd-passwdwhen someone leaves. - Move to new image versions when cloudimg publishes an rsync update (Step 12), and keep the operating system patched (unattended security upgrades are on).
- Back up the data volume (Step 11).
Support and licensing
rsync is free software under the GNU General Public License version 3 or later, with an exception that allows linking with OpenSSL and xxhash (the licence text is at /usr/local/share/doc/rsync/COPYING; source: https://download.samba.org/pub/rsync/src/rsync-3.5.1.tar.gz, https://github.com/RsyncProject/rsync). There is no per user or per CPU licence fee; the AMI price covers cloudimg's build, hardening, first boot setup and support. rsync is a trademark of its respective owner; cloudimg is not affiliated with or endorsed by the rsync project.
- Email: support@cloudimg.co.uk
- Website: https://www.cloudimg.co.uk
- Support: 24/7, with a 24 hour response SLA