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

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

pip install -e .

Enable the plugin in mirror.py's config.json:

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

The plugin's own settings live in rsync.json, not in the plugins block of config.json. See the Configuration section below.

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.0.1.tar.gz (20.9 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.0.1-py3-none-any.whl (16.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: mirror_py_rsync_server-1.0.1.tar.gz
  • Upload date:
  • Size: 20.9 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.0.1.tar.gz
Algorithm Hash digest
SHA256 00c65084d8f776801ac4890504a0dc54593c4632cbb7e2b06bac5b4275264289
MD5 4c624cf81321b04bb7ea221899c31c28
BLAKE2b-256 1daa4dc61694a597295120c042bdf9abcab04b5ade32b7c6ee936e2345177252

See more details on using hashes here.

Provenance

The following attestation bundles were made for mirror_py_rsync_server-1.0.1.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.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for mirror_py_rsync_server-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4a38e1231771ff2acfd98ac0620301504b3297c6ab0c5830f12ae29c4dbd3474
MD5 a5ad6d97cd39459464815b5a2eb15af1
BLAKE2b-256 8166a448b2a10e2a7c94a081f425f3cec47843d198d5de59a37da254f79256e6

See more details on using hashes here.

Provenance

The following attestation bundles were made for mirror_py_rsync_server-1.0.1-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