Backups do not exist; only tested restores exist. Keep that sentence, because it is the one idea in this lesson you cannot afford to forget. On srv-tramontana there have been backups for weeks: backup_tramontana.sh generates them, verifies their sha256sum, leaves them on a volume of their own and a systemd timer fires it every night. All of that sounds very good and proves absolutely nothing, because nobody has ever restored a single one. A backup that has not been restored is a hypothesis, not a protection. This lesson closes the module by turning that hypothesis into a tested procedure, with an agreed RPO and RTO, generational retention, incremental backups that do not grow out of control, encryption, verification and a runbook somebody could follow even if you were on holiday.
Contents
- What gets backed up and what does not: Tramontana's inventory
- RPO and RTO: how much we can lose and how long we can take
- The 3-2-1 rule and generational retention
- Full, incremental and differential
- Consistency: the file being written while you copy it
- Tools:
tar,rsync,ddandrestic - System backups versus rebuilding from code
- Encryption, custody and legal obligations
- Verification and the restore test
- Automating and watching the age of the last backup
- Restoring: Tramontana's three scenarios
- The recovery runbook
- What gets backed up and what does not: Tramontana's inventory
The first decision is not a technical one: it is deciding what deserves to be copied. The rule is simple: you back up what cannot be rebuilt.
| Category | Backed up? | Why |
|---|---|---|
| Business data (bookings, database, uploads) | Yes, first of all | Unrecoverable: they are the business |
Configuration (/etc, units, sudoers, fstab) |
Yes | Rebuildable, but it takes hours and details get forgotten |
Secrets (keys, certificates, db_password) |
Yes, encrypted and separately | Without them nothing starts; with them in the clear, the backup is a bomb |
| Operating system and packages | No: the list is enough | apt-mark showmanual reinstalls them |
| Application releases | Only the active one | The rest are in the artefact repository |
| Logs | According to the agreed retention | Forensic and legal value, not operational |
Caches, temporary files, /proc, /sys |
Never | They regenerate; they only take up space and slow things down |
Tramontana's concrete inventory, which is what is going to be copied:
/home/operator/data/bookings.csv # guests' personal data (CRITICAL) tramontana database # daily logical dump (CRITICAL) /opt/tramontana/shared/uploads/ # uploaded documents (CRITICAL) /etc/tramontana/ # app.conf, deploy.conf (HIGH) /etc/systemd/system/tramontana* # units and timers (HIGH) /etc/sudoers.d/tramontana, /etc/fstab, /etc/logrotate.d/tramontana (HIGH) /home/operator/scripts/ and bin/ # already versioned in git (MEDIUM) /opt/tramontana/releases/3.2.1/ # only the active release (MEDIUM) /opt/tramontana/HISTORY # the memory of the changes (HIGH) package list: apt-mark showmanual (MEDIUM)
- RPO and RTO: how much we can lose and how long we can take
Two acronyms that have to be agreed with Marta, not decided on your own:
- RPO (Recovery Point Objective): how much data we can afford to lose, measured in time. If the backup is daily at 02:30 and the server dies at 18:00, 15.5 hours of bookings are lost. Is that acceptable?
- RTO (Recovery Time Objective): how long the service can be down while it is restored.
Translated into Tramontana with real figures: about 25 bookings come in a day, with an average value of €313.70. Losing a whole day is around €7,842.50 in bookings that would have to be reconstructed by hand from the confirmation emails, with the reputational cost of ringing the guests.
| Scenario | Agreed RPO | Agreed RTO | What it means technically |
|---|---|---|---|
| Accidental deletion of a file | 24 h | 30 min | A daily backup is enough |
| A corrupt release | 0 | 15 min | A pre-deployment backup (it already exists) |
| Total loss of the server | 4 h | 8 h | A backup of the database every 4 hours and a copy off the server |
That 4-hour RPO for the database is the decision that changes the design: the daily 02:30 backup does not meet it, and a dump every four hours is needed. Every improvement in RPO or RTO costs money and complexity; that is why the decision belongs to the business, with your technical advice.
- The 3-2-1 rule and generational retention
The 3-2-1 rule sums up decades of disasters:
- 3 copies of the data (the original and two more).
- On 2 different media or systems.
- 1 of them off site.
Today on srv-tramontana we have one copy, on the same server, in the same building. If the disk fails in a way that takes the VG with it, or if somebody encrypts the machine, or if the office burns down, there is no copy. /srv/tramontana/backups is a convenience, not a protection. The modern variant adds a 1-0: at least one immutable or offline copy, and zero errors in the last verification, because modern ransomware seeks out and encrypts backup destinations reachable from the server.
GFS retention (Grandfather-Father-Son): not all backups are worth the same over time.
| Generation | Frequency | Kept | What for |
|---|---|---|---|
| Sons (daily) | Every day | 14 | Recent mistakes: something deleted yesterday |
| Fathers (weekly) | Sunday | 8 | Corruption detected weeks later |
| Grandfathers (monthly) | The 1st | 12 | Legal requirements and auditing |
With that, restic forget --keep-daily 14 --keep-weekly 8 --keep-monthly 12 leaves exactly the history you agreed, with no improvised decisions.
- Full, incremental and differential
| Type | What it copies | Space | Backup time | Restoring |
|---|---|---|---|---|
| Full | Everything, every time | Maximum | Maximum | The fastest: a single set |
| Incremental | What changed since the previous backup (whichever it was) | Minimum | Minimum | The slowest: the full one + all the incrementals, in order |
| Differential | What changed since the last full backup | Intermediate, growing | Intermediate | Medium: the full one + one differential |
The classic compromise: a weekly full plus daily incrementals. The incremental chain has a real risk that has to be said out loud: if one link is lost or corrupted, everything after it is unrecoverable. That is why you verify all of them, not just the last. Modern tools with deduplication (restic, borg) remove almost all of this dilemma: each backup behaves like a full one when restoring and takes up as much space as an incremental.
- Consistency: the file being written while you copy it
Copying a file while somebody is writing to it produces rubbish: the first half of the file is from before the change and the second half from after. In a database, that mixture is a backup that cannot be opened. Three solutions, in order of preference:
| Solution | How | Service interruption | When to use it |
|---|---|---|---|
| A hot dump from the application | pg_dump, mysqldump, a native export |
None | The best: the application guarantees coherence |
| An LVM snapshot (05-04) | Freezes the volume at one instant | Seconds | Files that have no dump of their own |
| Stopping the service | systemctl stop, copy, start |
As long as the copy takes | A last resort |
The snapshot in practice, applying what you learned in 05-04 and making use of the 5 GiB we deliberately left free in the VG:
sudo lvcreate -L 2G -s -n snap-backup /dev/vg-data/lv-backups
sudo mkdir -p /mnt/snap && sudo mount -o ro /dev/vg-data/snap-backup /mnt/snap
# ... copy from /mnt/snap, with the peace of mind of a frozen state ...
sudo umount /mnt/snap && sudo lvremove -y /dev/vg-data/snap-backupThe correct and complete sequence for Tramontana's database combines the first two: a logical dump with pg_dump (coherent by definition) and a snapshot for the uploads files, which have no dump of their own.
- Tools:
tar, rsync, dd and restic
tar, rsync, dd and restictar with incrementals
# Full backup: it creates the state file (snar) that records what was copied
sudo tar --listed-incremental=/srv/tramontana/backups/state.snar \
-czf /srv/tramontana/backups/full-$(date +%F).tar.gz /etc/tramontana /opt/tramontana/shared
# Incremental: the SAME .snar file; tar copies only what has changed since then
sudo tar --listed-incremental=/srv/tramontana/backups/state.snar \
-czf /srv/tramontana/backups/inc-$(date +%F).tar.gz /etc/tramontana /opt/tramontana/sharedThe .snar is the brain of the operation: if you lose it, the next "incremental" will be a full backup, and if you mix it between chains, the backup will be inconsistent. Keep it with the backups and take a separate copy of it. And inspect before extracting, as the course's convention requires:
rsync --link-dest: the trick you have to know
Here the circle closes with the hard links from 02-06. --link-dest compares against a previous backup and, for each file that has not changed, creates a hard link instead of copying the data. The result: each backup looks and restores like a full backup, but on disk it takes up only what has changed.
yesterday=$(date -d yesterday +%F)
today=$(date +%F)
rsync -aHAX --delete \
--link-dest="/srv/tramontana/backups/daily/$yesterday" \
/opt/tramontana/shared/ \
"/srv/tramontana/backups/daily/$today/"$ du -sh --apparent-size /srv/tramontana/backups/daily/2026-08-19
2.1G /srv/tramontana/backups/daily/2026-08-19
$ du -sh /srv/tramontana/backups/daily/2026-08-19
118M /srv/tramontana/backups/daily/2026-08-19It looks like 2.1 GiB — and when restoring it is — but it only consumes 118 MiB of new disk. Two warnings: hard links do not protect against the corruption of a block (all the copies share the same inode and therefore the same damage), and deleting the base copy breaks nothing, because the inode survives for as long as one link remains.
dd: full images and their danger
dd copies block by block, understanding nothing about files. It is good for cloning a whole disk or the boot sector, and it is the most dangerous command in this lesson: swapping if= and of= destroys the destination without asking. It is called "disk destroyer" for a reason.
It requires the device to be unmounted or frozen for the image to be consistent, and it copies the empty space as well. For regular data backups, it is almost never the answer.
restic: the modern solution
Deduplication, encryption as standard, integrity verification and declarative retention. Complete real-world usage:
export RESTIC_REPOSITORY=/srv/remote-backups/tramontana
export RESTIC_PASSWORD_FILE=/root/.restic-key # mode 0600, NEVER in the script
restic init # create the repository (once)
restic backup --tag daily /home/operator/data /etc/tramontana /opt/tramontana/shared
restic snapshots # what is stored
restic ls latest /home/operator/data # browse without restoring
restic restore latest --target /tmp/restore --include /home/operator/data/bookings.csv
restic forget --keep-daily 14 --keep-weekly 8 --keep-monthly 12 --prune
restic check --read-data-subset=10% # a real verification of the data$ restic backup --tag daily /home/operator/data /etc/tramontana
Files: 142 new, 3 changed, 1204 unmodified
Added to the repository: 41.882 MiB (12.204 MiB stored)
snapshot 8a3f2c19 savedNotice the 41.882 MiB added that occupy 12.204 MiB for real: that is deduplication plus compression. borg is equivalent in capability; rsnapshot is the classic version of the --link-dest trick, useful if you prefer backups you can browse with ls without an intermediate tool.
- System backups versus rebuilding from code
Copying the entire system (an image or a tar of /) lets you go back to exactly the previous state, but it produces enormous backups and drags along the accumulated rubbish, including any latent problem. The modern alternative is to rebuild the server from code: a clean machine, a playbook that installs and configures everything, and on top of that only the data restored from the backup.
| Approach | Advantages | Drawbacks |
|---|---|---|
| A system image | An exact return, fast | Enormous; it restores the problems too |
| Data + rebuilding from code | Small backups, a clean environment, reproducible | It demands maintaining the provisioning code and testing it |
Tramontana is heading towards the second, and that is why the inventory includes /etc/tramontana, the systemd units and the package list: they are the input for the future Ansible playbook you will see in 07-06. In the meantime, the package list is your insurance:
- Encryption, custody and legal obligations
An unencrypted backup is a leak waiting to happen. The original lives on a server with permissions, sudo, ACLs and systemd hardening; the copy ends up on a USB disk, in a bucket or in somebody's house, with none of those protections. And it contains exactly the same data.
Encrypt at source, before the copy leaves the server: restic and borg do it as standard, and with tar you chain gpg or age. Managing the keys — where they live, who has custody of them, how they are rotated, what happens if they are lost — is the subject of 06-05, and it is no small detail: an encrypted backup whose key has been lost is exactly as useful as having no backup at all.
Compliance warning (GDPR).
bookings.csvand the database contain guests' personal data (name, contact details, dates of stay). The backups inherit every obligation of the original: encryption at rest and in transit, documented access control, a record of who accesses them, retention limited to the time necessary, and — the point almost always forgotten — the right to erasure extends to backups as well, which makes it necessary to have a written policy on how a deletion request is handled when the data sits in immutable copies. And if the backup also goes to a cloud provider, the data processor and the location of the data come into play. None of this is for you to decide: it must be defined and approved by the data protection or compliance officer, and your job is to implement it and to be able to prove it.
- Verification and the restore test
An unverified backup is a file of reassuring size. There are three levels, and you have to do all three:
| Level | What it checks | Command |
|---|---|---|
| Integrity | The bits have not been corrupted | sha256sum -c backup.sha256 |
| Structure | The archive can be read from end to end | tar -tzf, restic check --read-data |
| Usefulness | The restored data works | A real restore and a functional check |
Only the third proves anything. The first two are automated; the third is scheduled:
$ sha256sum -c /srv/tramontana/backups/tramontana-2026-08-19.tar.gz.sha256
/srv/tramontana/backups/tramontana-2026-08-19.tar.gz: OK
$ tar -tzf /srv/tramontana/backups/tramontana-2026-08-19.tar.gz >/dev/null && echo "structure OK"
structure OK
$ restic check --read-data-subset=10%
no errors were foundThe periodic restore test is part of the procedure, not an extra: once a quarter, restore onto a clean VM, start the application, check that the 25 bookings are there and that the sum of the amounts comes to €7,842.50, time how long it took (does it meet the 8 h RTO?) and record the result with the date and the name of whoever did it. A restore test nobody has timed does not let you promise any RTO.
- Automating and watching the age of the last backup
You already have the automation from 05-05: tramontana-backup.service with its timer, Persistent=true and RequiresMountsFor. What is missing is the watching, and here is the industry's most common mistake: watching that the job ran instead of watching that there is a recent, valid backup. A script that fails silently and a disabled timer produce the same symptom: nothing. The metric that really matters is the age of the last correct backup.
#!/usr/bin/env bash
# /home/operator/scripts/check_backup.sh — silence if all is well
set -euo pipefail
source "$(dirname "$(readlink -f "$0")")/lib/common.sh"
readonly DEST="/srv/tramontana/backups"
readonly MAX_HOURS="${TRAMONTANA_MAX_BACKUP_HOURS:-30}"
main() {
local latest age_h
latest=$(find "$DEST" -maxdepth 1 -name 'tramontana-*.tar.gz' -printf '%T@ %p\n' \
| sort -rn | head -1 | cut -d' ' -f2-) || true
[[ -n "$latest" ]] || die 2 "there is no backup in $DEST"
age_h=$(( ( $(date +%s) - $(stat -c %Y "$latest") ) / 3600 ))
(( age_h <= MAX_HOURS )) || die 2 "the last backup is ${age_h}h old (maximum ${MAX_HOURS}h)"
sha256sum -c "${latest}.sha256" --status || die 2 "incorrect checksum in $latest"
log "backup correct: $(basename "$latest") (${age_h}h)"
}
main "$@"It is fired by its own timer at 08:00, after the backup window, and it only notifies when there is something to do: it is the principle of "silence if all is well" applied to the only metric that matters.
- Restoring: Tramontana's three scenarios
(a) Accidental deletion of bookings.csv
RPO 24 h, RTO 30 min. Luis ran an unfortunate mv at 11:40.
# 1. STOP the damage: stop the application writing over an inconsistent state
sudo systemctl stop tramontana.service
# 2. Locate the most recent backup and check WHAT it contains before touching anything
restic snapshots --tag daily | tail -3
restic ls latest /home/operator/data | grep bookings
# 3. Restore into a SEPARATE directory, never straight over the original
restic restore latest --target /tmp/rest --include /home/operator/data/bookings.csv
# 4. Verify the restored content BEFORE putting it in place
wc -l /tmp/rest/home/operator/data/bookings.csv # 26 (header + 25 bookings)
awk -F';' 'NR>1 {s+=$6} END {printf "%.2f\n", s}' /tmp/rest/home/operator/data/bookings.csv
# -> 7842.50
# 5. Put it in place with the right ownership and permissions, and start
sudo install -o operator -g tramontana -m 0640 \
/tmp/rest/home/operator/data/bookings.csv /home/operator/data/bookings.csv
sudo systemctl start tramontana.service && sudo -u operator ~/scripts/health_check.shStep 4 is what separates a restore from an act of faith: 26 lines and €7,842.50 are the file's known figures. If they do not add up, the backup is no good and you have to go to the previous one.
(b) A corrupt release that has to be rolled back
RPO 0, RTO 15 min. It is the case of 3.3.0, which weighs 99.2 MiB and does not start. deploy.sh already rolls back on its own (05-05), but if the fault is detected later:
ls -l /opt/tramontana/app # which release it points at now
sudo systemctl stop tramontana.service
sudo ln -sfn releases/3.2.1 /opt/tramontana/app.new
sudo mv -T /opt/tramontana/app.new /opt/tramontana/app # atomic switch
sudo tar -xzf /srv/tramontana/backups/pre-deploy/conf-3.2.1.tar.gz -C / # its config
sudo systemctl start tramontana.service
curl -sf -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/health # 200The daily backup plays no part here: the one that saves the day is the pre-deployment backup in /srv/tramontana/backups/pre-deploy/, and the relative symbolic link makes it possible to go back in a second. This is 02-06 and 05-05 working together.
(c) Total loss of the server
RPO 4 h, RTO 8 h. The scenario everybody avoids thinking about. The complete procedure:
- A new machine: Ubuntu Server 24.04 LTS, the same
hostname, the same partitioning scheme with/varisolated (01-04). - Identities first, and with the same numbers, or the permissions from the restore will not add up:
groupadd -g 1002 tramontana,useradd -r -u 997 -g tramontana -s /usr/sbin/nologin svc-tramontana, plusoperatorandluis(05-01). - Packages:
xargs -a packages-2026-08-19.txt sudo apt install --no-install-recommends -y, with the database'shold(05-03). - Disks: recreate the PV, VG and LV, format and mount
/srv/tramontana/backupsby UUID withnofail, andmount -abefore rebooting (05-04). - Data:
restic restore <snapshot> --target /, and the database dump withpsql < dump.sql. - Configuration and services: restore
/etc/tramontana, the units,sudoers.d,logrotate.d;systemctl daemon-reload;systemctl enable --now tramontana.service tramontana-backup.timer(05-05, 05-06). - Verify:
health_check.sh, count the 25 bookings, check the total of €7,842.50, an emptysystemctl --failed, and test a real booking from start to finish. - Time it and write down how long it took. That number is the real RTO, and it is the one you can promise.
Notice that this procedure uses all eight lessons of the module. That is the point of Module 5.
- The recovery runbook
A runbook is the document that lets somebody else carry out the recovery, in the small hours, in a hurry and without you. It must contain:
- An inventory of what is backed up, where it goes and how often.
- The agreed RPO and RTO, with who approved them and when.
- Where the encryption keys are and who has custody of them (not the key: where it is).
- The procedures for the three scenarios, with literal, copyable commands.
- Contacts: who decides, who executes, who tells the customers.
- The date and result of the last restore test, and who did it.
And the most important part: it cannot be kept only on the server you are going to lose. A printed copy, an external git repository, the company's document management system. A runbook that exists only in /opt/tramontana/HISTORY is a runbook that disappears in scenario (c), precisely when you need it.
sudo tee -a /opt/tramontana/HISTORY >/dev/null <<'END'
2026-08-19 Backup and restore (operator, approved by Marta Vidal)
- RPO/RTO: 4h/8h for total loss; DB dump every 4h in addition to the daily backup
- restic in /srv/remote-backups + replica off the server (3-2-1 destination pending)
- GFS retention: 14 daily, 8 weekly, 12 monthly
- check_backup.sh + 08:00 timer: warns if the last backup is over 30h old or the sha256 fails
- Full restore test: 2026-08-19, 3h 42min (8h RTO met). Runbook held off the server.
ENDCommon Mistakes and Tips
- Never having restored. It is this lesson's mistake. Schedule the quarterly test today, with a date and a person responsible.
- The backup on the same server. A fire, a ransomware encryption or a VG failure takes the original and the copy. 3-2-1, no excuses.
- Losing the
.snarfile fromtar --listed-incremental, or mixing it between chains: the incremental backup stops being recoverable. - Copying a live database with
cp. It produces a useless file. A native dump or a snapshot. - Unencrypted backups leaving the server, or encrypted ones with a key nobody has custody of. Both are equally serious.
- Watching the job instead of the result. What matters is the age of the last correct backup, not that the script finished.
- Restoring straight over the original. Restore to a separate directory, verify and then put it in place.
- Infinite retention "just in case". It costs money and clashes with the GDPR: retention is agreed and documented.
- Tip: time every test restore. The RTO you can promise is the one you have measured, not the one you would like.
Exercises
- Designing the scheme. Starting from the 4 h RPO and the 8 h RTO agreed with Marta, describe Tramontana's complete backup scheme: what is copied, how often, with which tool, where each copy goes and what retention it has. Justify where the 3-2-1 rule fails today.
- Verifying without a full restore. Write the commands that check, without touching production, that last night's backup contains
bookings.csvwith the 25 bookings and that the sum of the amounts is correct. Explain why this does not replace a restore test. - The missing link. You have a full backup from Sunday and six
tarincrementals. Wednesday's is corrupt. Up to which day can you restore, and why? What would you have done differently so that this problem did not exist?
Solutions
1.
| What | Frequency | Tool | Destination | Retention |
|---|---|---|---|---|
| Database dump | Every 4 h | pg_dump + restic |
The local restic repository and a replica off site | 14 d / 8 wk / 12 months |
bookings.csv, uploads, /etc |
Daily, 02:30 | restic backup |
The same | The same |
Active release and HISTORY |
Daily | restic backup |
The same | 14 daily |
| Pre-deployment configuration | On every deployment | tar (deploy.sh) |
/srv/tramontana/backups/pre-deploy |
10 deployments |
| Package list | Weekly | apt-mark showmanual |
With the backup | 8 weekly |
Where 3-2-1 fails today: there is one single copy (the "3" fails), on the same server and the same logical disk (the "2" fails) and with none off site (the "1" fails). The acceptable minimum is to add a replica of the restic repository to a remote destination with append-only credentials, so that a compromise of the server does not allow the history to be deleted.
2.
$ restic snapshots --latest 1 --json | jq -r '.[0].time'
2026-08-19T02:30:41+02:00
$ restic ls latest /home/operator/data | grep bookings.csv
/home/operator/data/bookings.csv
$ restic dump latest /home/operator/data/bookings.csv | wc -l
26
$ restic dump latest /home/operator/data/bookings.csv \
| awk -F';' 'NR>1 {n++; s+=$6} END {printf "%d bookings, %.2f EUR\n", n, s}'
25 bookings, 7842.50 EURrestic dump extracts a file to stdout without writing anything to disk, so the check does not touch production and needs no space.
Why it does not replace a restore test: this verifies one file, not the whole set; it does not check permissions, owners or ACLs; it does not validate that the restored database starts or that the application works with that data; and, above all, it times nothing, so it does not let you claim that the RTO is met. Verifying is necessary; restoring is what proves it.
3. You can restore up to Tuesday: Sunday's full backup plus Monday's and Tuesday's incrementals. Wednesday's is corrupt, and since each tar --listed-incremental increment contains only what has changed since the previous one, Thursday's, Friday's and Saturday's depend on a state you can no longer reconstruct. A file modified on Wednesday and never touched again exists only in the broken link.
What would have avoided the problem, in order of effectiveness:
- Verifying every backup as it is created (
tar -tzfandsha256sum), not just the last one: on Wednesday you would have known it had to be repeated. - Using differentials instead of incrementals: each one depends only on the full backup, so a broken link costs one day, not four.
- Better still, using a tool with deduplication and verification such as
restic, where each snapshot restores on its own andrestic check --read-datadetects corruption before you need it.
Conclusion
You have closed Module 5, and with it the distance between "I have scripts" and "I run a server". Look back at what has changed on srv-tramontana since you started:
- 05-01 — Identities stopped being magic: the
tramontanagroup (gid 1002) and thesvc-tramontanaservice account (uid 997, with no shell and no password) genuinely exist, withoperatorandluisin the group and ownership of/opt/tramontanaand/srv/tramontana/backupsin its place. - 05-02 —
sudostopped being a magic word: there is a written, validated, documented rule in/etc/sudoers.d/tramontana, plus SGID on the shared directories, ACLs so that Luis reads the logs without joiningadm, capabilities instead of SUID andchattr +ionapp.conf. - 05-03 — The software has provenance: deb822 repositories with keys in
/etc/apt/keyrings/, the database pinned withholdand pinning, and unattended security updates that warn without rebooting on their own. - 05-04 — The backups live on their own LVM volume that grows while in use, mounted by UUID with
nofail, with margin in the VG for snapshots and anfstabtested withmount -a. - 05-05 — The application is a real service: a hardened
tramontana.service, with automatic restart and cgroup limits, and the nightly backup turned intotramontana-backup.service+.timerwithPersistent=true;deploy.shfinally restarts. - 05-06 — The server has a memory: a persistent, capped journal,
/etc/logrotate.d/tramontanatested in simulation, the scripts writing to the journal, and the exact answer to "what happened last night at three?". - 05-07 — And it has a thermometer: a baseline with thresholds,
sysstatkeeping history, the USE method and an eleven-step procedure that has already solved the morning slowness by measuring before and after. - 05-08 — And now it has a safety net: an RPO and RTO agreed with Marta, the 3-2-1 rule, GFS retention, consistency through a dump and an LVM snapshot,
resticwith deduplication and encryption, verification at three levels, watching the age of the last correct backup and three restore procedures written, tested and timed.
None of this was "knowing commands". It was building a system that stands up when you are not in front of it, and that is exactly the difference between using Linux and administering it.
And yet everything you have built in this module has a door wide open. srv-tramontana listens on 8080 with no firewall, the network configuration is still the one the installer left, SSH accepts passwords and root logins without anybody having reviewed sshd_config, the db_password sits in the clear inside app.conf, the booking traffic — with the guests' personal data you have taken such care to protect in the backups — travels unencrypted, and in /var/log/btmp there are already forty-seven login attempts from an IP nobody has blocked. In Module 6: Networking and Security you close that door: you will configure the network persistently with netplan, you will harden SSH with keys and no root, you will raise a firewall that only lets through what is essential, you will detect and stop intrusions, you will get the secrets out of the configuration files and put TLS in front of the application, and you will finish by applying a complete hardening with AppArmor and a password policy that today is still the factory one. You have made a server that works; now it is time to make it defensible. Update your VM snapshot, keep the runbook off the machine and I will see you in Module 6.
Linux Course: From Beginner to System Administrator
Module 1: Introduction to Linux
- What Is Linux?
- History of Linux
- Linux Distributions
- Installing Linux
- First Contact with the System
- The Linux File System Structure
Module 2: Basic Linux Commands
- Introduction to the Command Line
- Getting Help and System Documentation
- Navigating the File System
- File and Directory Operations
- Viewing and Editing Files
- Hard and Symbolic Links
- File Permissions and Ownership
Module 3: Advanced Command-Line Skills
- The Shell Environment: Variables, Aliases and History
- Using Wildcards and Regular Expressions
- Searching Files and Content: find, locate and grep
- Pipes and Redirection
- Text Processing: cut, sort, uniq, sed and awk
- Process Management
- Scheduling Tasks with Cron
- Networking Commands
Module 4: Shell Scripting
- Introduction to Shell Scripting
- Variables and Data Types
- Script Input, Output and Arguments
- Control Structures
- Functions and Libraries
- Debugging and Error Handling
- Production Scripts: Best Practices
Module 5: System Administration
- User and Group Management
- sudo and Special Permissions
- Package Management
- Disk Management
- systemd and Service Management
- System Logs: journald and syslog
- System Monitoring and Performance Tuning
- Backup and Restore
Module 6: Networking and Security
- Network Configuration
- SSH and Remote Access
- Firewalls and Perimeter Security
- Intrusion Detection Systems
- Secrets Management and TLS Certificates
- Securing Linux Systems
Module 7: Advanced Topics
- The Boot Process and System Recovery
- Advanced Diagnostics: strace, perf and eBPF
- Linux Kernel Tuning
- Virtualization with Linux
- Linux Containers and Docker
- Automation with Ansible
- High Availability and Load Balancing
