- Python 62%
- Shell 33.8%
- CSS 3%
- Dockerfile 1.2%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| certs | ||
| config | ||
| doc | ||
| src | ||
| .gitignore | ||
| CHANGELOG.md | ||
| DISCLAIMER.md | ||
| docker-compose.yml | ||
| LICENSE | ||
| NOTICE | ||
| README.md | ||
| VERSION.md | ||
packagemini — RouterOS firmware mirror
A self-hosted RouterOS firmware mirror: it periodically fetches .npk packages and bundle zips
from MikroTik's official servers, serves them over HTTP/HTTPS via Caddy, and generates a themed
web UI plus an Atom feed. Routers fetch firmware from your mirror instead of
download.mikrotik.com — just swap the hostname.
Standalone (no dependency on rosbackup-ng), rootless, and self-hardening, with a one-command Rocky Linux 9 installer that doubles as the manager.
Features
- Mirrors RouterOS firmware — choose channels (stable / long-term / testing / development),
per-channel retention, architectures, and packages (
main-only/ named /all-extras). - Drop-in fetch paths —
/routeros/<version>/…, plus CHR images, netinstall, WinBox, and an Atom feed (/feed.xml). - Atomic downloads — files are never half-served; in-progress versions stay hidden until complete.
- Caddy front door — Let's Encrypt TLS via DNS-01 (deSEC, works on isolated hosts), rate limiting, IP allow/deny, optional Basic Auth, security headers.
- Monitoring — JSON access logs, an optional GoAccess board at
/goaccess, monthly reports. - Rootless & hardened — containers run as
uid/gid 1000; the installer hardens the host (key-only SSH, fail2ban incl. a web-flood jail, automatic security updates, sysctl, firewall, tight file perms). Seedoc/SYSTEM-HARDENING.md.
Requirements
- A Rocky Linux 9 host (also RHEL / AlmaLinux / CentOS Stream 9). The installer sets up Docker.
- For HTTPS: a public FQDN and a deSEC API token (DNS-01).
- Disk: ~30–50 GB with the defaults — see disk sizing.
Install
Clone the repository onto the host and run src/deploy.sh as root. It installs Docker, hardens the
host, opens the firewall, generates config, and brings up the stack. Idempotent.
# on the server (as root):
dnf install -y git
git clone https://git.jdneer.com/jd/rosbackup-packagemini.git /opt/packagemini
cd /opt/packagemini
sudo ./src/deploy.sh # first run creates packagemini.yml from the example and stops
$EDITOR packagemini.yml # set public_base_url, channels, architectures, …
sudo ./src/deploy.sh # builds + starts the mirror
Cloning (rather than copying) also means ./src/deploy.sh status shows the exact commit, and
git pull && sudo ./src/deploy.sh --all updates the mirror in place.
Everything in one go (mirror + GoAccess monitor + lazydocker TUI + sysadmin tools):
sudo ./src/deploy.sh --all
# à la carte: --with-monitor --with-lazydocker --with-tools --docker-only --no-harden
The sync worker starts immediately and repeats on sync_interval (default 6 h); the web container
serves files as soon as the first sweep writes them. The run is non-interactive once configured
(preset any first-run answer via env for unattended installs — see ./src/deploy.sh --help).
Manage
src/deploy.sh is also the manager — run it from anywhere (it operates on the repo root):
sudo ./src/deploy.sh status # health, security, mirror config, content, sync
sudo ./src/deploy.sh start | stop | restart # compose lifecycle
sudo ./src/deploy.sh logs [service] # follow logs
sudo ./src/deploy.sh refresh # trigger a sync sweep now
sudo ./src/deploy.sh harden # enable/disable hardening measures (interactive)
sudo ./src/deploy.sh set-fqdn <fqdn> # migrate to a new hostname (cert re-issues)
sudo ./src/deploy.sh set-cert # import/replace a manual TLS cert (renewals)
sudo ./src/deploy.sh set-mirror-auth on|off # HTTP basic auth on the mirror
sudo ./src/deploy.sh open-goaccess # print the GoAccess board URL
sudo ./src/deploy.sh clear-config [data] # uninstall / reconfigure
Full workflow + every command: doc/MANAGE.md (or ./src/deploy.sh --help).
Point a router at the mirror
/tool fetch url="https://<mirror>/routeros/<ver>/routeros-<ver>.npk" mode=https
The listing at https://<mirror>/routeros/<ver>/ shows every file for that version.
Configure
Settings live in packagemini.yml (copy config/packagemini.example.yml); secrets go in .env
(config/env.example), managed by deploy.sh. Every option is annotated in the example file.
Backup/restore is just copying the host-bound data/, logs/, reports/ directories.
Documentation
- doc/MANAGE.md — day-to-day management workflow + every
deploy.shcommand. - doc/DESIGN.md — architecture, full configuration reference, package semantics, TLS, rate limiting, timezones, monitoring, disk sizing.
- doc/SYSTEM-HARDENING.md — host hardening + fail2ban/firewall ops.
- doc/MANUAL-X509-CERT.md — import your own TLS certificate (PEM).
- CHANGELOG.md · VERSION.md
Repository layout
docker-compose.yml # the stack (build contexts point at src/*)
src/ deploy.sh, sync/, web/, monitor/ # installer/manager + container build contexts
config/ packagemini.example.yml, env.example
doc/ DESIGN.md, SYSTEM-HARDENING.md, TODO.md
Runtime files (packagemini.yml, .env, data/, logs/, reports/) live at the repo root and
are gitignored; the live .env stays there so docker-compose auto-loads it.
License
Apache-2.0 — see LICENSE, NOTICE, and DISCLAIMER.md.