Rsync Server on Ubuntu 24.04 on Azure User Guide
Overview
This image runs rsync in daemon mode, known as rsyncd, fully installed and configured on Ubuntu 24.04 LTS as a hardened systemd service. rsync is the de facto standard tool for fast, efficient file synchronisation, mirroring and backup: its delta transfer algorithm sends only the parts of files that have changed, so repeated syncs of large trees complete in a fraction of the time and bandwidth of a full copy. Within minutes of launch a working rsync server is answering on the network.
The daemon listens on TCP port 873 and exposes one named module, cloudimg, mapped to a directory on a dedicated data disk. Clients connect with the rsync protocol, for example rsync file rsync://user@server/cloudimg/, to push files to the server or pull files from it.
Secure by default — no known bootstrap credential and no anonymous access. A naive rsync daemon exposes modules with no authentication and no isolation. This image does the opposite: the cloudimg module requires a module user and password on every transfer, there is no anonymous access, and every transfer is chrooted inside the module directory so a client can never escape it. There is no baked or shared credential — on the first boot of your instance a one shot service generates a unique module user and a long random password for that specific virtual machine and writes them to a root owned file at /root/rsync-credentials.txt. No two instances share a credential.
What is included:
- rsync 3.2.x from the official Ubuntu 24.04 archive, running as
rsync.serviceunder systemd on TCP 873. - One authenticated, chrooted module,
cloudimg, whose file store lives on a dedicated data disk mounted at/srv/rsync. - A per instance module user and password generated on first boot, written to
/root/rsync-credentials.txt(readable only by root). - A fully patched base with unattended security upgrades enabled, paired with this deployment guide and 24/7 cloudimg support.
Prerequisites
- The virtual machine deployed from this image, with SSH access as
azureuser. - Recommended virtual machine size:
Standard_B2s(2 vCPU, 4 GB RAM) to start. - A network security group (NSG) rule allowing inbound TCP 873 from the client hosts that will synchronise with the server. Restrict the source to your own client addresses — the rsync protocol authenticates every transfer, but you should still scope port 873 to the machines that need it.
- An rsync client on the machine you will synchronise from. rsync ships with almost every Linux and macOS system; on Windows it is available through WSL or cwRsync.
Verify the rsync server is running
SSH into the virtual machine as azureuser and confirm the daemon is active and listening on TCP 873.
rsync --version | head -1
sudo systemctl is-active rsync
sudo ss -ltn | grep ':873 '
You should see the rsync version line, active, and a listener bound to 0.0.0.0:873 (and its IPv6 equivalent [::]:873). The server is now answering the rsync protocol.

Retrieve the per instance credentials
The module user and password for this specific virtual machine were generated on first boot and written to a root owned file. Read them with sudo.
sudo cat /root/rsync-credentials.txt
The file contains RSYNC_USER, RSYNC_PASSWORD, RSYNC_MODULE (which is cloudimg), and a sample RSYNC_ENDPOINT. These values are unique to this instance and are not baked into the image. Keep the file secret. The screenshot below has the password masked.

Synchronise files with the rsync server
rsync reads the module password from the RSYNC_PASSWORD environment variable, so transfers are non interactive. The commands below run on the server itself against 127.0.0.1 to demonstrate a full round trip; the same commands work from any remote client once you replace 127.0.0.1 with the virtual machine's IP address.
Push a file to the server, then pull it back from the server and confirm the contents match:
RSYNC_USER=$(sudo grep '^RSYNC_USER=' /root/rsync-credentials.txt | cut -d= -f2-)
export RSYNC_PASSWORD=$(sudo grep '^RSYNC_PASSWORD=' /root/rsync-credentials.txt | cut -d= -f2-)
echo "hello from cloudimg $(date -u)" > /tmp/demo.txt
rsync -av /tmp/demo.txt "rsync://${RSYNC_USER}@127.0.0.1/cloudimg/"
rsync -av "rsync://${RSYNC_USER}@127.0.0.1/cloudimg/demo.txt" /tmp/demo-pulled.txt
cmp -s /tmp/demo.txt /tmp/demo-pulled.txt && echo "ROUND-TRIP OK: contents match"
The first rsync uploads demo.txt into the cloudimg module (stored on the data disk under /srv/rsync/cloudimg), the second downloads it back, and cmp confirms the two files are identical. You should see rsync's transfer summary for each direction and ROUND-TRIP OK: contents match.

To synchronise a whole directory from a remote client, point rsync at the module URL using the module user, with <public-ip> replaced by your virtual machine's public IP. The delta algorithm transfers only what changed, and --delete keeps the server an exact mirror of the source:
export RSYNC_PASSWORD='the-password-from-the-credentials-file'
rsync -av --delete ./my-local-folder/ rsync://your-user@<public-ip>/cloudimg/backup/
Confirm anonymous and wrong password access is rejected
Security is enforced on every transfer. An anonymous request (no credentials) and a request with the wrong password are both refused; only a request presenting the correct module user and password succeeds.
RSYNC_USER=$(sudo grep '^RSYNC_USER=' /root/rsync-credentials.txt | cut -d= -f2-)
rsync rsync://127.0.0.1/cloudimg/demo.txt /tmp/anon.txt </dev/null >/dev/null 2>&1; echo "anonymous transfer rejected (non-zero exit code ${?})"
RSYNC_PASSWORD='not-the-password' rsync "rsync://${RSYNC_USER}@127.0.0.1/cloudimg/demo.txt" /tmp/bad.txt >/dev/null 2>&1; echo "wrong-password transfer rejected (non-zero exit code ${?})"
Both commands fail with a non zero exit code because the module rejects unauthenticated and incorrectly authenticated transfers, and every successful transfer is chrooted inside the module directory.

Use rsync over SSH for encrypted transport
The rsync protocol on port 873 authenticates every transfer but does not encrypt the data in transit. For sensitive data, or to avoid opening port 873 at all, run rsync over SSH instead. This reuses the virtual machine's existing SSH access as azureuser, encrypts the whole transfer, and needs no rsync daemon configuration:
rsync -av -e ssh ./my-local-folder/ azureuser@<public-ip>:/srv/rsync/cloudimg/backup/
With rsync over SSH you can close inbound TCP 873 in the NSG entirely and rely only on SSH (TCP 22). Choose the daemon (port 873) for high throughput inside a trusted network, and rsync over SSH when transport encryption matters.
Add another module
The whole server configuration lives in a single text file, /etc/rsyncd.conf. To expose another directory, create a module directory on the data disk with sudo install -d -o rsyncd -g rsyncd -m 0770 /srv/rsync/another-module, then add a new block to /etc/rsyncd.conf (edit with sudo nano /etc/rsyncd.conf). New modules should also set auth users and secrets file so they are authenticated:
[another-module]
comment = a second authenticated module
path = /srv/rsync/another-module
use chroot = yes
read only = no
uid = rsyncd
gid = rsyncd
auth users = your-user
secrets file = /etc/rsyncd.secrets
strict modes = yes
Add the matching your-user:your-password line to /etc/rsyncd.secrets (keep it mode 0600), then reload the daemon with sudo systemctl restart rsync.
Point your rsync clients at the server
From any machine with an rsync client, synchronise against the module URL using the module user and password from /root/rsync-credentials.txt. Set RSYNC_PASSWORD in the environment so transfers are non interactive, and scope the NSG so only your own client hosts can reach TCP 873. For scheduled backups, drive the same command from cron or a systemd timer on the client, and use --delete to keep the server an exact mirror of the source.
Support
This image is provided by cloudimg with 24/7 technical support. Contact support@cloudimg.co.uk for help with deployment and first boot configuration, retrieving the per instance credentials, designing rsync modules, scheduling backups and mirrors, running rsync over SSH, tuning bandwidth and connection limits, restricting access with hosts allow rules and the Azure NSG, managing the dedicated data disk, and rsync version upgrades. Critical issues receive a one hour average response time.
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.