# aptly-mirror.sh A comprehensive bash script to create and maintain aptly mirrors for Debian and Ubuntu repositories. Automate the mirroring of package repositories, create time-based snapshots, and publish merged snapshot sets to serve to clients. ## Features - **Multi-distribution support**: Mirror Debian 11/12/13 and Ubuntu 20.04/22.04/24.04/26.04 - **Flexible mirroring**: Mirror main, updates, and security streams separately - **Snapshot management**: Create dated snapshots of mirrors and merge them - **Automatic publishing**: Publish snapshots as APT repositories for client consumption - **Retention policy**: Keep only N recent snapshot sets, automatically cleanup old ones - **GPG verification**: Verify repository signatures during download and signing - **Bandwidth control**: Optional download speed limiting - **Syslog integration**: All operations logged to syslog for monitoring ## Getting Started ### Prerequisites - `aptly` (>= 1.4.0): Install via your system package manager or from [aptly.info](https://www.aptly.info/) - `gpg`: For GPG key management (usually pre-installed) - Bash 4+ - Sufficient disk space for mirror storage (50GB+ recommended depending on architecture count) ### Installation 1. **Clone or download the script**: ```bash git clone aptly-mirror cd aptly-mirror ``` 2. **Create configuration**: ```bash cp aptly-mirror.conf.example aptly-mirror.conf ``` 3. **Edit configuration** for your environment: ```bash nano aptly-mirror.conf ``` Key settings: - `ARCHITECTURES`: CPU architectures to mirror (e.g., `"amd64"` or `"amd64 arm64"`) - `KEEP_SNAPSHOTS`: Number of old snapshot sets to retain (default: `2`) 4. **Make the script executable**: ```bash chmod +x aptly-mirror.sh ``` 5. **Import GPG keys** (recommended for production): ```bash ./aptly-mirror.sh import-keys ``` 6. **Create initial mirrors**: ```bash ./aptly-mirror.sh create ``` This may take 10-30 minutes depending on your network and disk speed. 7. **Create initial snapshots and publish**: ```bash ./aptly-mirror.sh publish ``` ### Verify Setup List all mirrors, snapshots, and published repositories: ```bash ./aptly-mirror.sh list ``` Check syslog for operation logs: ```bash journalctl -t aptly-mirror -f ``` ## Manual ### Commands #### `create` — Initialize all mirrors Create mirrors for all configured Debian and Ubuntu releases. Mirrors are created empty and must be populated with the first `update` command. ```bash ./aptly-mirror.sh create ``` **Output**: - Creates mirrors for each release: - `debian-{codename}-main` - `debian-{codename}-updates` - `debian-{codename}-security` - Similar pattern for Ubuntu **Time**: 1-2 minutes #### `update` — Fetch latest packages and republish Updates all mirrors to the latest packages, creates timestamped snapshots, merges them, and publishes a fresh snapshot set. This is the main command to run regularly. ```bash ./aptly-mirror.sh update ``` **Process**: 1. Updates all existing mirrors (downloads new packages) 2. Creates dated snapshots (e.g., `debian-bullseye-main-20260408123045`) 3. Merges main + updates + security snapshots for each release 4. Publishes or switches the published repository to the merged snapshot **Time**: 5-30 minutes (depends on network, disk speed, and download limit) **Output example**: ``` Repositories are published under /var/aptly/public/ Client sources.list entries: deb http:///debian bullseye main contrib non-free deb http:///debian bookworm main contrib non-free non-free-firmware deb http:///ubuntu focal main restricted universe multiverse ``` #### `publish` — Snapshot and publish current state Creates fresh snapshots of current mirrors without updating them. Useful when you want to take a snapshot without fetching new packages. ```bash ./aptly-mirror.sh publish ``` **Use cases**: - Create a point-in-time snapshot after verifying upstream stability - Re-publish without re-fetching packages #### `cleanup` — Remove old snapshots and optimize database Removes old snapshot sets beyond the `KEEP_SNAPSHOTS` retention limit and runs aptly's database cleanup. ```bash ./aptly-mirror.sh cleanup ``` **Safety**: - Only removes snapshots that are not currently published - Never removes the active published snapshot - Safe to run after each update #### `list` — Show all mirrors, snapshots, and published repos Display the current state of all mirrors, snapshots, and published repositories. ```bash ./aptly-mirror.sh list ``` #### `import-keys` — Import GPG signing keys Imports GPG keys for verifying Debian and Ubuntu repository signatures. Requires network access to GPG keyserver. ```bash ./aptly-mirror.sh import-keys ``` **Notes**: - Only needs to run once during setup - Requires `~/.gnupg/` to exist - Keyserver can be customized via `GPG_KEYSERVER` in config ### Options #### `-c ` — Specify config file ```bash ./aptly-mirror.sh -c /etc/aptly-mirror.conf update ``` Config file search order (if `-c` not specified): 1. `$APTLY_MIRROR_CONF` environment variable 2. `./aptly-mirror.conf` (same directory as script) 3. `/etc/aptly-mirror.conf` #### `-h`, `--help` — Show usage ```bash ./aptly-mirror.sh --help ``` ### Configuration All settings are in `aptly-mirror.conf`. See the included example for detailed comments. **Key settings**: | Setting | Default | Description | |---------|---------|-------------| | `ARCHITECTURES` | `amd64` | Architectures to mirror (space-separated) | | `KEEP_SNAPSHOTS` | `2` | Number of old snapshot sets to retain | | `DOWNLOAD_LIMIT` | `0` | Speed limit in KiB/s (0 = unlimited) | | `IGNORE_SIGNATURES` | `0` | Skip GPG verification (not recommended) | | `SKIP_SIGNING` | `0` | Skip GPG signing when publishing | ### Logging All output is logged via syslog with tag `aptly-mirror`. View logs with: ```bash # Follow in real-time journalctl -t aptly-mirror -f # View recent entries journalctl -t aptly-mirror -n 50 # Search for errors journalctl -t aptly-mirror | grep ERROR ``` Older systemd-free systems can check `/var/log/syslog`: ```bash grep aptly-mirror /var/log/syslog ``` ## Sample Crontab Run weekly updates every Sunday at 2 AM: ```bash # Edit crontab crontab -e # Add this line: 0 2 * * 0 /home/dak/Code/aptly/aptly-mirror.sh update ``` **Full recommended setup** with logging and error notifications: ```bash # Weekly update and cleanup 0 2 * * 0 /home/dak/Code/aptly/aptly-mirror.sh update && /home/dak/Code/aptly/aptly-mirror.sh cleanup # Check syslog for errors (runs at 3 AM, 1 hour after update) 0 3 * * 0 journalctl -t aptly-mirror -n 100 | grep -i error && echo "aptly-mirror errors detected" | mail -s "aptly-mirror Alert" admin@example.com ``` **Multiple updates per week**: ```bash # Every 12 hours (twice daily) 0 2,14 * * * /home/dak/Code/aptly/aptly-mirror.sh update # Cleanup on Sundays 0 4 * * 0 /home/dak/Code/aptly/aptly-mirror.sh cleanup ``` **For systemd systems** (alternative to cron): Create `/etc/systemd/system/aptly-mirror.timer`: ```ini [Unit] Description=Weekly aptly mirror update After=network-online.target Wants=network-online.target [Timer] OnCalendar=Sun *-*-* 02:00:00 Persistent=true [Install] WantedBy=timers.target ``` Create `/etc/systemd/system/aptly-mirror.service`: ```ini [Unit] Description=Update aptly mirrors After=network-online.target [Service] Type=oneshot ExecStart=/home/dak/Code/aptly/aptly-mirror.sh update ExecStartPost=/home/dak/Code/aptly/aptly-mirror.sh cleanup User=aptly StandardOutput=journal StandardError=journal ``` Enable and start: ```bash sudo systemctl daemon-reload sudo systemctl enable aptly-mirror.timer sudo systemctl start aptly-mirror.timer ``` ## Troubleshooting ### "Mirror already exists" This is normal on repeated runs. The script skips existing mirrors. ### GPG signature verification failures Either: - Import keys: `./aptly-mirror.sh import-keys` - Or skip verification (not recommended): set `IGNORE_SIGNATURES=1` in config ### Disk space exhausted Monitor with: ```bash du -sh ~/.aptly/ ``` Reduce `KEEP_SNAPSHOTS` in config, or clean up old mirrors manually via `aptly mirror drop`. ### Network timeout during update Set a `DOWNLOAD_LIMIT` to avoid overwhelming the network, or run during off-peak hours. ### Can't write to log Ensure log directory exists and is writable. Check that `LOG_DIR` in config is accessible. ## AI Attribution AIA EAI Hin R Claude Code v1.0 This work was entirely AI-generated. AI was prompted for its contributions, or AI assistance was enabled. AI-generated content was reviewed and approved. The following model(s) or application(s) were used: Claude Code. ## License MIT