Rs
Storage Azure

Rsync Server on Ubuntu 24.04 on Azure User Guide

| Product: Rsync Server on Ubuntu 24.04 LTS on Azure

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.service under 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.

The rsync service reports active under systemd, ss shows the daemon listening on TCP port 873 on all interfaces for both IPv4 0.0.0.0 and IPv6, and rsync reports version 3.2.7 protocol version 31

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.

The per instance credentials file at /root/rsync-credentials.txt showing the generated rsync module user, the password masked, the module name cloudimg, and a sample rsync endpoint, all unique to this virtual machine and generated on first boot

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.

An rsync push of a file into the cloudimg module over the rsync protocol showing the transfer summary, followed by an rsync pull of the same file back from the server, and cmp confirming the round trip contents match, with the file stored on the dedicated data disk

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.

An anonymous rsync request to the cloudimg module being refused with an authentication failure and a non zero exit code, followed by a request with a wrong password also being refused, and the rsyncd.conf showing use chroot yes, an authenticated auth users line, and the secrets file, proving the module rejects unauthenticated transfers and jails every transfer

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.