https://repo.example.com/debian/
https://repo.example.com/debian/
https://repo.example.com/debian/
sudo apt update
sudo apt install -y aptly nginx gpg
sudo apt update
sudo apt install -y aptly nginx gpg
sudo apt update
sudo apt install -y aptly nginx gpg
aptly version
nginx -v
gpg --version | head -n 1
aptly version
nginx -v
gpg --version | head -n 1
aptly version
nginx -v
gpg --version | head -n 1
gpg --quick-gen-key "Homelab Repo Signing Key <[email protected]>" rsa4096 sign 1y
gpg --quick-gen-key "Homelab Repo Signing Key <[email protected]>" rsa4096 sign 1y
gpg --quick-gen-key "Homelab Repo Signing Key <[email protected]>" rsa4096 sign 1y
gpg --list-secret-keys --keyid-format long
gpg --list-secret-keys --keyid-format long
gpg --list-secret-keys --keyid-format long
gpg --armor --export "Homelab Repo Signing Key <[email protected]>" > repo-signing-key.asc
gpg --armor --export "Homelab Repo Signing Key <[email protected]>" > repo-signing-key.asc
gpg --armor --export "Homelab Repo Signing Key <[email protected]>" > repo-signing-key.asc
sudo install -d -m 0755 /var/www/repo
sudo install -m 0644 repo-signing-key.asc /var/www/repo/repo-signing-key.asc
sudo install -d -m 0755 /var/www/repo
sudo install -m 0644 repo-signing-key.asc /var/www/repo/repo-signing-key.asc
sudo install -d -m 0755 /var/www/repo
sudo install -m 0644 repo-signing-key.asc /var/www/repo/repo-signing-key.asc
aptly -architectures="amd64" \ mirror create debian-bookworm-main \ https://deb.debian.org/debian/ \ bookworm \ main
aptly -architectures="amd64" \ mirror create debian-bookworm-main \ https://deb.debian.org/debian/ \ bookworm \ main
aptly -architectures="amd64" \ mirror create debian-bookworm-main \ https://deb.debian.org/debian/ \ bookworm \ main
aptly mirror update debian-bookworm-main
aptly mirror update debian-bookworm-main
aptly mirror update debian-bookworm-main
SNAPSHOT="bookworm-main-$(date -u +%Y%m%d)"
aptly snapshot create "$SNAPSHOT" from mirror debian-bookworm-main
SNAPSHOT="bookworm-main-$(date -u +%Y%m%d)"
aptly snapshot create "$SNAPSHOT" from mirror debian-bookworm-main
SNAPSHOT="bookworm-main-$(date -u +%Y%m%d)"
aptly snapshot create "$SNAPSHOT" from mirror debian-bookworm-main
aptly snapshot list
aptly snapshot list
aptly snapshot list
aptly publish snapshot \ -distribution="bookworm" \ -component="main" \ "$SNAPSHOT" \ debian
aptly publish snapshot \ -distribution="bookworm" \ -component="main" \ "$SNAPSHOT" \ debian
aptly publish snapshot \ -distribution="bookworm" \ -component="main" \ "$SNAPSHOT" \ debian
~/.aptly/public
~/.aptly/public
~/.aptly/public
/home/<user>/.aptly/public
/home/<user>/.aptly/public
/home/<user>/.aptly/public
server { listen 80; server_name repo.example.com; location /debian/ { alias /home/repo/.aptly/public/; autoindex on; } location = /repo-signing-key.asc { root /var/www/repo; }
}
server { listen 80; server_name repo.example.com; location /debian/ { alias /home/repo/.aptly/public/; autoindex on; } location = /repo-signing-key.asc { root /var/www/repo; }
}
server { listen 80; server_name repo.example.com; location /debian/ { alias /home/repo/.aptly/public/; autoindex on; } location = /repo-signing-key.asc { root /var/www/repo; }
}
sudo ln -s /etc/nginx/sites-available/repo.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo ln -s /etc/nginx/sites-available/repo.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo ln -s /etc/nginx/sites-available/repo.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
curl -I http://repo.example.com/debian/dists/bookworm/Release
curl -I http://repo.example.com/repo-signing-key.asc
curl -I http://repo.example.com/debian/dists/bookworm/Release
curl -I http://repo.example.com/repo-signing-key.asc
curl -I http://repo.example.com/debian/dists/bookworm/Release
curl -I http://repo.example.com/repo-signing-key.asc
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://repo.example.com/repo-signing-key.asc \ | sudo gpg --dearmor -o /etc/apt/keyrings/homelab-repo-archive-keyring.gpg
sudo chmod 0644 /etc/apt/keyrings/homelab-repo-archive-keyring.gpg
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://repo.example.com/repo-signing-key.asc \ | sudo gpg --dearmor -o /etc/apt/keyrings/homelab-repo-archive-keyring.gpg
sudo chmod 0644 /etc/apt/keyrings/homelab-repo-archive-keyring.gpg
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://repo.example.com/repo-signing-key.asc \ | sudo gpg --dearmor -o /etc/apt/keyrings/homelab-repo-archive-keyring.gpg
sudo chmod 0644 /etc/apt/keyrings/homelab-repo-archive-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/homelab-repo-archive-keyring.gpg] https://repo.example.com/debian bookworm main' \ | sudo tee /etc/apt/sources.list.d/homelab-repo.list >/dev/null
echo 'deb [signed-by=/etc/apt/keyrings/homelab-repo-archive-keyring.gpg] https://repo.example.com/debian bookworm main' \ | sudo tee /etc/apt/sources.list.d/homelab-repo.list >/dev/null
echo 'deb [signed-by=/etc/apt/keyrings/homelab-repo-archive-keyring.gpg] https://repo.example.com/debian bookworm main' \ | sudo tee /etc/apt/sources.list.d/homelab-repo.list >/dev/null
sudo apt update
apt-cache policy | sed -n '/repo.example.com/,+4p'
sudo apt update
apt-cache policy | sed -n '/repo.example.com/,+4p'
sudo apt update
apt-cache policy | sed -n '/repo.example.com/,+4p'
aptly mirror update debian-bookworm-main NEW_SNAPSHOT="bookworm-main-$(date -u +%Y%m%d)-2"
aptly snapshot create "$NEW_SNAPSHOT" from mirror debian-bookworm-main aptly publish switch bookworm debian "$NEW_SNAPSHOT"
aptly mirror update debian-bookworm-main NEW_SNAPSHOT="bookworm-main-$(date -u +%Y%m%d)-2"
aptly snapshot create "$NEW_SNAPSHOT" from mirror debian-bookworm-main aptly publish switch bookworm debian "$NEW_SNAPSHOT"
aptly mirror update debian-bookworm-main NEW_SNAPSHOT="bookworm-main-$(date -u +%Y%m%d)-2"
aptly snapshot create "$NEW_SNAPSHOT" from mirror debian-bookworm-main aptly publish switch bookworm debian "$NEW_SNAPSHOT"
aptly snapshot list
aptly snapshot list
aptly snapshot list
aptly publish switch bookworm debian bookworm-main-20260404
aptly publish switch bookworm debian bookworm-main-20260404
aptly publish switch bookworm debian bookworm-main-20260404
sudo apt update
sudo apt upgrade
sudo apt update
sudo apt upgrade
sudo apt update
sudo apt upgrade
# /etc/systemd/system/aptly-snapshot-refresh.service
[Unit]
Description=Refresh aptly mirror and create a new snapshot
After=network-online.target
Wants=network-online.target [Service]
Type=oneshot
User=repo
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/bash -lc '
set -euo pipefail
aptly mirror update debian-bookworm-main
SNAPSHOT="bookworm-main-$(date -u +%%Y%%m%%d-%%H%%M%%S)"
aptly snapshot create "$SNAPSHOT" from mirror debian-bookworm-main
'
# /etc/systemd/system/aptly-snapshot-refresh.service
[Unit]
Description=Refresh aptly mirror and create a new snapshot
After=network-online.target
Wants=network-online.target [Service]
Type=oneshot
User=repo
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/bash -lc '
set -euo pipefail
aptly mirror update debian-bookworm-main
SNAPSHOT="bookworm-main-$(date -u +%%Y%%m%%d-%%H%%M%%S)"
aptly snapshot create "$SNAPSHOT" from mirror debian-bookworm-main
'
# /etc/systemd/system/aptly-snapshot-refresh.service
[Unit]
Description=Refresh aptly mirror and create a new snapshot
After=network-online.target
Wants=network-online.target [Service]
Type=oneshot
User=repo
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/bash -lc '
set -euo pipefail
aptly mirror update debian-bookworm-main
SNAPSHOT="bookworm-main-$(date -u +%%Y%%m%%d-%%H%%M%%S)"
aptly snapshot create "$SNAPSHOT" from mirror debian-bookworm-main
'
# /etc/systemd/system/aptly-snapshot-refresh.timer
[Unit]
Description=Run aptly snapshot refresh daily [Timer]
OnCalendar=*-*-* 02:15:00
Persistent=true [Install]
WantedBy=timers.target
# /etc/systemd/system/aptly-snapshot-refresh.timer
[Unit]
Description=Run aptly snapshot refresh daily [Timer]
OnCalendar=*-*-* 02:15:00
Persistent=true [Install]
WantedBy=timers.target
# /etc/systemd/system/aptly-snapshot-refresh.timer
[Unit]
Description=Run aptly snapshot refresh daily [Timer]
OnCalendar=*-*-* 02:15:00
Persistent=true [Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now aptly-snapshot-refresh.timer
sudo systemctl list-timers aptly-snapshot-refresh.timer
sudo systemctl daemon-reload
sudo systemctl enable --now aptly-snapshot-refresh.timer
sudo systemctl list-timers aptly-snapshot-refresh.timer
sudo systemctl daemon-reload
sudo systemctl enable --now aptly-snapshot-refresh.timer
sudo systemctl list-timers aptly-snapshot-refresh.timer
apt-cache policy openssl
apt-cache madison openssl
apt-cache policy openssl
apt-cache madison openssl
apt-cache policy openssl
apt-cache madison openssl
du -sh ~/.aptly
aptly mirror list
aptly snapshot list
aptly publish list
du -sh ~/.aptly
aptly mirror list
aptly snapshot list
aptly publish list
du -sh ~/.aptly
aptly mirror list
aptly snapshot list
aptly publish list
aptly snapshot drop old-snapshot-name
aptly snapshot drop old-snapshot-name
aptly snapshot drop old-snapshot-name - a controlled rollout window
- a predictable staging-to-production promotion
- a quick rollback after a bad package update
- a stable package source for disconnected or bandwidth-limited environments - mirror them locally
- turn the current state into an immutable snapshot
- publish that snapshot as your own APT repository
- switch clients to a newer or older snapshot when you decide - Cache: makes downloads faster
- Snapshot mirror: makes package state deterministic - keep a local mirror of upstream packages
- snapshot a known-good state
- publish that state under your own URL
- republish clients to a newer snapshot later with aptly publish switch
- switch back to an older snapshot if needed - mirror host: runs aptly, gpg, and nginx
- client hosts: consume the published repository over HTTP - update the upstream mirror
- create a new snapshot
- switch the published repo to that snapshot - automation creates the candidate snapshot
- you test it on staging
- you run aptly publish switch only after approval - repeatable patching across many hosts
- staged promotions from test to production
- rollback speed after bad upstream updates
- auditable change windows
- offline or bandwidth-constrained environments - aptly overview: https://www.aptly.info/doc/overview/
- aptly mirror create: https://www.aptly.info/doc/aptly/mirror/create/
- aptly mirror update: https://www.aptly.info/doc/aptly/mirror/update/
- aptly snapshot create: https://www.aptly.info/doc/aptly/snapshot/create/
- aptly publish snapshot: https://www.aptly.info/doc/aptly/publish/snapshot/
- aptly publish switch: https://www.aptly.info/doc/aptly/publish/switch/
- Debian sources.list(5) man page: https://manpages.debian.org/bookworm/apt/sources.list.5.en.html
- nginx autoindex module: https://nginx.org/en/docs/http/ngx_http_autoindex_module.html