Skip to main content

mirror.py event plug-in that generates rsyncd.conf and rsyncd.secrets from the package list.

Project description

mirror.py rsync-server plugin

An event plugin for mirror.py that generates rsyncd.conf and rsyncd.secrets from the live mirror package list plus a sidecar rsync.json configuration file. The plugin regenerates both files automatically when the mirror daemon starts (MASTER.INIT.POST) and whenever the package set changes via mirror config reload (MASTER.CONFIG_RELOAD.POST).

How it works

The plugin listens on two mirror.py events:

  • MASTER.INIT.POST — fires once when the master daemon finishes starting up.
  • MASTER.CONFIG_RELOAD.POST — fires after mirror config reload has loaded a new configuration. Until the mirror.py core ships this event, regeneration happens at daemon start only; the listener signature accepts (*args, **kwargs) so it is forward-compatible.

File generation only. The plugin writes rsyncd.conf and rsyncd.secrets; it does not start, stop, or signal the rsyncd process. This is intentional: rsyncd re-reads rsyncd.conf and the secrets file on every incoming client connection, so adding or removing mirror modules takes effect immediately with no reload signal needed.

Writes are atomic (via a temporary file in the same directory followed by os.replace). If the generated content is identical to what is already on disk, the file is not rewritten. Regeneration runs under a module-level lock so concurrent event firings do not race.

Packages with settings.hidden: true are completely excluded — they appear in neither the public nor the private module list.

Installation

Requires mirror.py >= 1.3.0 (uses the 1.3.0 plugin API: API version gate and the per-plugin config-file mechanism).

Install the plugin into the same Python environment as mirror.py:

pip install -e .

Enable the plugin in mirror.py's config.json. As of mirror.py 1.3.0 the plugins block is enable-only:

"plugins": { "rsync-server": { "enabled": true } }

Any config sub-block here is ignored — the plugin's own settings live in rsync.json (see the Configuration section below).

Scaffold rsync.json

The plugin supports mirror plugin config create:

mirror plugin config create rsync-server

This writes an example rsync.json (mode 0600, since it holds plaintext passwords).

Caveat: during mirror plugin config create the mirror config path is not loaded, so the file is written to the fixed fallback location /etc/mirror/rsync.json regardless of any --config flag. --config only points the command at a valid config.json so the plugin registry can load; it does not change where the scaffold is written. If your mirror config lives elsewhere, move the generated file next to your config.json, or copy rsync.json.example manually. (At daemon runtime the config path is known, so generation and reads use rsync.json next to your config.json.)

Configuration

rsync.json must live in the same directory as mirror.py's config.json (default path: /etc/mirror/rsync.json).

See rsync.json.example for a complete, realistic example.

All keys are optional and fall back to the defaults listed below.

Key Type Default Description
rsyncd_conf string (absolute path) /etc/rsyncd.conf Destination path for the generated rsyncd.conf.
secrets_file string (absolute path) /etc/rsyncd.secrets Destination path for the generated secrets file. Also emitted as secrets file in the global section of rsyncd.conf.
users object {} Map of username to password. Written to the secrets file in insertion order.
global object {} Raw rsyncd parameter passthrough. Keys and values are emitted in insertion order as key = value lines in the global section. Values may be strings, integers, or booleans (booleans render as true/false). The key secrets file is managed by the plugin and is rejected if placed here.
private_modules.enabled boolean true When false, no [.Name] private module sections are generated.
private_modules.auth_users string * Value written to auth users in every private module section.
private_modules.list boolean false Value written to list in every private module section.
private_modules.lock_file string (absolute path) /var/run/rsyncd-private.lock Value written to lock file in every private module section. The private modules share this lock file, giving them a separate max-connections accounting pool independent of the public modules.

Unknown top-level keys and unknown private_modules keys are rejected with a ValueError at load time (typo protection). Any validation failure leaves previously generated files untouched.

SECURITY NOTE: rsync.json contains plaintext passwords. Restrict its permissions:

chmod 600 /etc/mirror/rsync.json

The plugin logs a warning if rsync.json is group- or other-readable. The generated rsyncd.secrets file is always written with mode 0600, as required by rsyncd's strict modes.

Generated output

Given a package with id archlinux (display name ArchLinux), src = rsync://rsync.archlinux.org/ftp_tier1 and dst = /mirror/ftp/ArchLinux, and the global settings from rsync.json.example, the plugin produces:

# WARNING: DO NOT EDIT!! Generated by the mirror.py rsync-server plugin.
uid = rsync
gid = nogroup
use chroot = no
max connections = 20
motd file = /mirror/etc/motd
log file = /var/log/geoul/rsyncd/all.log
transfer logging = yes
log format = %o %a - %u [%t] "%P/%f" - %l
pid file = /var/run/rsyncd.pid
exclude = .~tmp~

secrets file = /mirror/etc/rsyncd.secrets

[archlinux]
    path = /mirror/ftp/ArchLinux
    comment = from rsync://rsync.archlinux.org/ftp_tier1

[.archlinux]
    path = /mirror/ftp/ArchLinux
    comment = private module for ArchLinux without connection limits for authorized mirrors
    auth users = *
    list = false
    lock file = /var/run/rsyncd-private.lock

Each package produces a public/private module pair:

  • [pkgid] is the public module. The module name is the package id, not the display name, so it is a valid rsyncd module token (no spaces or special characters). It is visible in rsync host:: listings and carries a comment = from <upstream src> line. The comment line is omitted when a package has no upstream src (for example, locally synced packages).
  • [.pkgid] is the authenticated, unlisted private twin. The leading dot hides it from rsync host:: listings. Access is gated by auth users and the secrets file. This module has its own lock file, so its connection accounting is independent of the public module's max connections limit.

Modules are sorted by package id. The static header contains no timestamp so that identical content is detected and the file is not rewritten unnecessarily.

The secrets file (rsyncd.secrets) contains one username:password line per entry in users, written in insertion order, with no header line.

Running rsyncd

Point rsyncd at the generated configuration file:

rsync --daemon --config=/etc/rsyncd.conf

Operational notes

Changing users or rsync settings. Edit rsync.json, then run:

mirror config reload

No daemon restart is needed for module or authentication changes. rsyncd picks up the new rsyncd.conf and rsyncd.secrets on the next incoming client connection.

Parameters that require an rsyncd restart. Daemon-socket parameters such as port, address, and pid file are read by rsyncd only at startup. Changing them in rsync.json and running mirror config reload will update the generated file, but rsyncd itself must be restarted for these to take effect. Module-level parameters (path, auth, comment, etc.) apply per connection and do not require a restart.

Private module connection accounting. The private modules share the lock file specified by private_modules.lock_file. This gives them a separate max-connections pool rather than unlimited connections — the pool size is controlled by rsyncd's global max connections parameter applied against that lock file independently from the public modules' lock file.

Development

Set up a virtual environment and install the plugin alongside mirror.py:

uv venv
uv pip install -e /path/to/mirror.py -e . pytest

Run the test suite:

uv run pytest

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mirror_py_rsync_server-1.1.0.tar.gz (22.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mirror_py_rsync_server-1.1.0-py3-none-any.whl (17.5 kB view details)

Uploaded Python 3

File details

Details for the file mirror_py_rsync_server-1.1.0.tar.gz.

File metadata

  • Download URL: mirror_py_rsync_server-1.1.0.tar.gz
  • Upload date:
  • Size: 22.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mirror_py_rsync_server-1.1.0.tar.gz
Algorithm Hash digest
SHA256 5168de43e5e34e9b2c7595eaa84ed3b56338de78fdaac4d909463cd813e4d6a8
MD5 56402ae0707f4a7b5c9274b3a2859749
BLAKE2b-256 78e5cbff3eeb9a5ea0455415fb1a02ebbcc1f04811c48273fcd32fa52e5e0562

See more details on using hashes here.

Provenance

The following attestation bundles were made for mirror_py_rsync_server-1.1.0.tar.gz:

Publisher: pypi.yaml on sparcs-kaist/mirror.py-rsync-server

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mirror_py_rsync_server-1.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for mirror_py_rsync_server-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0bf768d866d7bcbcd5fe015940e565821a8859246dbc64a614cc7df5febaf6da
MD5 fcae75e600f105a68f36858a8523e349
BLAKE2b-256 f97fab71d1c5fdcc698f17575b80703834b49e7f1a90f0803cda81dff996a944

See more details on using hashes here.

Provenance

The following attestation bundles were made for mirror_py_rsync_server-1.1.0-py3-none-any.whl:

Publisher: pypi.yaml on sparcs-kaist/mirror.py-rsync-server

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page