GuidesDevelopers and hostingLinux mirror with rsync

Run a Linux mirror with rsync

A public or private mirror of Arch Linux, EndeavourOS or CachyOS on Debian 13, synced the way each distribution asks on a timer, and served over HTTP and HTTPS by a rootless container behind Caddy.

Tested on Arch Linux and EndeavourOS sources on Debian 13 (trixie) on a Melonslab server Updated September 25, 2026

Recommended server for this guide

VC-S Micro · 2 vCPU · 8 GB Memory · 250 GB Storage

Month to month, no lock-in 7-day money-back guarantee

€7.99/mo

Deploy now
On this page

What you will set up

A mirror is a full copy of a distribution's packages that stays in step with the original and serves them to others. A public mirror helps the distribution and everyone near you; a private one serves only your own machines.

Here, a user of its own called mirror:

  • syncs with rsync on a timer, the way each distribution asks mirrors to,
  • runs a small web server container that serves the files, behind Caddy from the Podman guide,
  • over both plain HTTP and HTTPS, as distributions expect of mirrors.

For your own servers only, a package cache is usually the better choice: it keeps only what you install. Arch Linux asks you to consider one before setting up a private Arch mirror.

Every step below was run on a Melonslab server with Debian 13. The EndeavourOS repository was synced completely and pacman on Arch Linux installed from it. Arch Linux's own sync script was set up and its update check run, and the sync it would make was measured; a full copy did not fit on the test server's disk. Both HTTP and HTTPS served the files without redirecting.

Which distributions fit

DistributionSizePlan
Arch Linux, as its own script syncs it285 GBStandard with 500 GB or more
EndeavourOS, packages only0.25 GBany
EndeavourOS, with installer images93 GBany Standard plan
CachyOS197 GBStandard with 500 GB or more
Debian, amd64 with sourcesabout 1,450 GBmore storage: ask our sales team
Ubuntuabout 3,600 GBmore storage: ask our sales team
Alpine Linuxabout 4,800 GBmore storage: ask our sales team
Rocky Linuxabout 7,400 GBmore storage: ask our sales team

We measured the sizes on 2026-09-25; Debian's, Ubuntu's and Alpine's come from the projects' own figures. They grow over time, so leave room. The last four need more storage than our Standard plans have: our sales team can set that up, and for your own servers only, the package cache needs a few gigabytes instead. This guide's sync steps cover the Arch Linux family.

Before you start

You need:

  • a server set up as in the Podman guide, with Caddy running, and disk space from the table above;
  • a name for the mirror, such as mirror.example.com, with an A record and an AAAA record pointing at your server.

1. Install rsync and curl

As root:

apt update
apt install -y rsync curl

Arch Linux's sync script uses curl to check for changes before it runs rsync.

2. Create the user

useradd -m -s /bin/bash mirror
loginctl enable-linger mirror
machinectl shell mirror@

3. Serve the files

mkdir -p ~/mirror ~/bin ~/.config/containers/systemd ~/.config/systemd/user

Create ~/.config/containers/systemd/mirror-web.container:

[Unit]
Description=File server for the mirror

[Container]
ContainerName=mirror-web
Image=docker.io/library/caddy:2
Volume=%h/mirror:/srv:ro
# Only Caddy, on this server, can reach it: the port is not open to the internet.
PublishPort=127.0.0.1:8086:8080
Exec=caddy file-server --root /srv --browse --listen :8080
AutoUpdate=registry

[Service]
Restart=always

[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user start mirror-web
systemctl --user enable --now podman-auto-update.timer

The files stay in the mirror user's home, which no other user can read, so this user serves them itself, read-only, with directory listings.

4. Put Caddy in front

Go back to root with exit, switch to machinectl shell caddy@, and add this block to the end of ~/Caddyfile:

# Both HTTP and HTTPS, without redirecting: distributions expect plain HTTP on mirrors.
http://mirror.example.com, https://mirror.example.com {
    reverse_proxy 127.0.0.1:8086
}

Restart Caddy with systemctl --user restart caddy. Naming both http:// and https:// stops Caddy from sending plain HTTP visitors on to HTTPS. Packages are signed, so pacman can trust them over either.

5. Sync a distribution

Go back to the mirror user with exit and machinectl shell mirror@. Then set up one or more of the following.

Arch Linux

Arch Linux publishes the script its mirrors use. It first checks a small lastupdate file over HTTPS, and only runs rsync when that has changed. Download it, and set it up to sync from accum.se in Umeå, one of Arch's Tier 1 mirrors:

curl -o ~/bin/syncrepo-archlinux https://gitlab.archlinux.org/archlinux/infrastructure/-/raw/main/roles/syncrepo/files/syncrepo-template.sh
sed -i \
  -e 's|^target=.*|target="$HOME/mirror/archlinux"|' \
  -e 's|^lock=.*|lock="$HOME/.syncrepo-archlinux.lock"|' \
  -e 's|^source_url=.*|source_url="rsync://mirror.accum.se/mirror/archlinux/"|' \
  -e 's|^tls=.*|tls=0|' \
  -e 's|^lastupdate_url=.*|lastupdate_url="https://mirror.accum.se/mirror/archlinux/lastupdate"|' \
  ~/bin/syncrepo-archlinux
chmod +x ~/bin/syncrepo-archlinux

tls=0 is needed because accum.se does not offer rsync over TLS. Create ~/.config/systemd/user/sync-archlinux.service:

[Unit]
Description=Sync the Arch Linux mirror

[Service]
Type=oneshot
ExecStart=%h/bin/syncrepo-archlinux

And ~/.config/systemd/user/sync-archlinux.timer:

[Unit]
Description=Sync the Arch Linux mirror every hour, on a fixed random minute

[Timer]
OnCalendar=hourly
RandomizedDelaySec=1h
FixedRandomDelay=true

[Install]
WantedBy=timers.target

Run the first sync by hand, which shows its progress and copies about 285 GB, then switch on the timer:

~/bin/syncrepo-archlinux
systemctl --user daemon-reload
systemctl --user enable --now sync-archlinux.timer

From then on the timer checks every hour, always on the same randomly chosen minute, as Arch asks of its mirrors. When nothing has changed, a run takes a few seconds.

EndeavourOS

Create ~/bin/sync-endeavouros:

#!/bin/sh
# Sync EndeavourOS. flock stops a run from starting while the last one is still going.
exec flock -n "$HOME/.sync-endeavouros.lock" \
  rsync -rlptH --safe-links --delete-delay --delay-updates --timeout=600 \
  rsync://alpix.eu.rsync.endeavouros.com/endeavouros/ "$HOME/mirror/endeavouros/"

That syncs the packages and the installer images, 93 GB. For the packages only, add repo/ to both paths. Make it executable with chmod +x ~/bin/sync-endeavouros, and create a service and timer as for Arch Linux, named sync-endeavouros, with ExecStart=%h/bin/sync-endeavouros. Start the service once for the first sync, then enable the timer.

--delay-updates and --delete-delay keep the mirror consistent while it syncs: new files appear together at the end, and old ones are removed after that.

CachyOS

CachyOS allows mirrors, but does not publish where to sync from. Write to admin@cachyos.org, who will give you an rsync source. Then copy the EndeavourOS script to ~/bin/sync-cachyos, put their source in place of the EndeavourOS one and $HOME/mirror/cachyos/ as the target, and add a service and timer the same way. CachyOS mirrors keep the packages under repo/, as the line in step 6 expects; check that yours does after the first sync.

6. Check it

Open https://mirror.example.com/: the directory listing shows each distribution you sync. To use the mirror from pacman, put it first in the mirror list:

DistributionFileLine
Arch Linux/etc/pacman.d/mirrorlistServer = https://mirror.example.com/archlinux/$repo/os/$arch
EndeavourOS/etc/pacman.d/endeavouros-mirrorlistServer = https://mirror.example.com/endeavouros/repo/$repo/$arch
CachyOS/etc/pacman.d/cachyos-mirrorlistServer = https://mirror.example.com/cachyos/repo/$arch/$repo

7. Keep it private, or make it public

Private. To let only your own machines in, add an address check to the Caddy block, as in the package cache guide.

Public. Each distribution lists public mirrors itself, after checking them:

  • Arch Linux: open a feature request at gitlab.archlinux.org/archlinux/arch-mirrors (you need to log in), naming the Tier 1 mirror you sync from. Its mirrors sync all of the upstream mirror, at most once an hour and at least once a day, on a random minute, which the steps above do.
  • EndeavourOS: email alpix at endeavouros.com. It asks for at least 100 Mbit/s, IPv4, a sync at least every 3 hours, and no Cloudflare in front, and watches a new mirror for a week or two before listing it.
  • CachyOS: ask when you get your rsync source.

Troubleshooting

The Arch Linux sync fails to connect on port 874. tls is still 1: accum.se only offers plain rsync. Check the sed step.

A sync does not start. The last one is still running: the lock file makes a second run exit straight away. systemctl --user status sync-archlinux shows what it is doing.

The disk fills up. Compare du -sh ~/mirror/* with the table above, which grows over time.

Running a public mirror?

A public mirror serves steady, heavy traffic: a popular one sends many terabytes a month. Talk to our sales team before you open one to the public, so we can plan the capacity with you.

Run it on your own server

VC-S Micro

€7.99/mo

vCPU
2
Memory
8 GB
Storage
250 GB
Transfer
10 TB
Standard
HDD · RAID 10
  • Full root access
  • Native /64 IPv6
  • RAID-protected storage
  • Malmö, Sweden
  • Month to month, no lock-in
  • 7-day money-back guarantee
All guides