[{"data":1,"prerenderedAt":191},["ShallowReactive",2],{"seo-verification":3,"blog-linux-vps-hardening-checklist-for-agencies-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"id":7,"slug":8,"slugs":9,"title":13,"excerpt":14,"readTime":15,"views":16,"isPinned":17,"publishedAt":18,"category":19,"categories":25,"featuredImage":27,"bgImage":28,"posterImage":29,"relatedSolution":27,"intro":30,"sections":31,"ctaTitle":142,"ctaBody":143,"ctaButton":144,"ctaUrl":145,"relatedPosts":146},317,"linux-vps-hardening-checklist-for-agencies",{"fr":10,"en":8,"ar":11,"es":12},"linux-hardening-vps-checklist","قائمة-تصليب-خادم-لينكس-للوكالات-بعد-التسليم","hardening-linux-vps-checklist-para-agencias-tras-la-entrega","Linux VPS Hardening Checklist for Agencies","Reproducible Linux hardening checklist for agencies: auditd, sudo user, SSH key auth, UFW, fail2ban and root lockout — with per-client traceability.",11,0,false,"2026-08-30T00:00:00+00:00",{"id":20,"name":21,"slug":22,"color":23,"icon":24},8,"Security & Monitoring","securite-monitoring","bg-rose-500\u002F10 text-rose-400","security",[26],{"id":20,"name":21,"slug":22,"color":23,"icon":24},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Flinux-hardening-vps-checklist-poster.svg","Your agency delivers a VPS and each technician applies \"roughly the same thing\" — without a written runbook, without a trace. When an incident occurs, you cannot prove that the agreed security configuration was actually applied. This guide picks up where the individual tutorial leaves off: standardisation, delegation and traceability for a portfolio of client servers.",[32,36,46,49,59,68,77,83,89,98,101,133,136,139],{"type":33,"title":34,"body":35},"h2","Why a formalised runbook changes everything for an agency","An individual developer can mentally apply five commands after each delivery. An agency cannot: multiple technicians, dozens of client VPS servers, rotating on-call shifts. When a client reports suspicious access six months after production launch, the question is not \"did you secure the server?\" — it's \"can you prove it?\"\n\nTraceability has become a contractual and regulatory requirement. The **NIS2 directive** (national transposition underway across the EU) and **GDPR** require service providers handling personal data to document the security measures they have implemented. Without a versioned runbook and `auditd` logs, your agency has no defensible evidence.\n\nThis guide does not re-describe installing fail2ban or UFW — the articles \u003Ca href=\"\u002Fblog\u002Fproteger-vps-fail2ban\">Protecting a VPS with fail2ban\u003C\u002Fa> and \u003Ca href=\"\u002Fblog\u002Fpare-feu-ufw-vps\">UFW firewall on VPS\u003C\u002Fa> cover that in detail. It operates at a higher level: how to standardise, delegate and trace these actions across an entire client portfolio.",{"type":37,"title":38,"items":39},"ul","What this runbook brings to your agency",[40,41,42,43,44,45],"**Reproducibility**: every technician follows exactly the same steps, in the same order, on each new client VPS.","**Traceability**: `auditd` records who did what, when, and which command — preservable proof for incidents or client audits.","**Safe delegation**: a junior can deliver a hardened server without improvising, because the runbook already contains the decisions.","**Contractual defence**: a security clause in your maintenance contract is only enforceable with a dated execution log.","**Reduced attack surface**: the checklist eliminates classic omissions — root SSH left open, auditd not activated — the most commonly exploited entry points.","**Cross-client consistency**: same secure baseline for all clients, differences only where the client's specification requires them.",{"type":33,"title":47,"body":48},"Prerequisites and scope of the checklist","This checklist targets **Ubuntu 24.04 LTS** and **Debian 12** (Bookworm), the two most common distributions on VPS servers in 2026. Commands have been verified on these systems; on AlmaLinux or Rocky Linux, package names and service paths differ.\n\nMinimum VPS requirements: 1 vCPU, 1 GB RAM (2 GB recommended when fail2ban and auditd run together), 20 GB SSD. ServOrbit delivers each VPS with immediate root SSH access and an included KVM console, allowing your agency to apply this runbook from the very first minute — without going through an intermediate access request to the hosting provider.\n\nThe checklist is organised into **seven blocks**, in application order. It stops at the basic system scope: application security (exposed backoffice, application attack surfaces) is covered separately in \u003Ca href=\"\u002Fblog\u002Fbackoffice-vps-surfaces-attaque-oubliees-2026\">Exposed backoffice: overlooked attack surfaces on VPS\u003C\u002Fa>.",{"type":50,"title":51,"steps":52},"steps","Block 1 — Updates and initial inventory",[53,56],{"title":54,"body":55},"System update and inventory","The first action after root login is to bring the system to its current patch level.\n\n```bash\napt update && apt upgrade -y\napt install -y auditd audispd-plugins curl gnupg2 ufw fail2ban\n```\n\nRecord in your runbook: the date, kernel version (`uname -r`), and the list of installed packages (`dpkg -l > \u002Froot\u002Finventory-$(date +%F).txt`). This inventory file constitutes the server's **baseline** at delivery — it is the evidence you produce if a client disputes the initial state of their machine.\n\n**CIS Benchmark reference**: CIS control 1.1 (Ubuntu Linux 24.04 LTS Benchmark, \"Initial Setup\" section).",{"title":57,"body":58},"Enable automatic security updates","```bash\napt install -y unattended-upgrades\ndpkg-reconfigure --priority=low unattended-upgrades\n```\n\nVerify that the `Unattended-Upgrade::Allowed-Origins` line includes `${distro_id}:${distro_codename}-security`. For a client portfolio, enable automatic updates and schedule a monthly review of non-security updates — those require human validation.\n\n**CIS reference**: CIS control 1.9 (Ensure updates, patches, and additional security software are installed).",{"type":50,"title":60,"steps":61},"Block 2 — Sudo user and root lockout",[62,65],{"title":63,"body":64},"Create a dedicated administration account","Never use `root` for day-to-day tasks. Create a named account per technician or an agency service account:\n\n```bash\nuseradd -m -s \u002Fbin\u002Fbash adminagency\nusermod -aG sudo adminagency\npasswd adminagency\n```\n\n**Agency tip**: use an identifiable account name in logs (`john.doe` or `agency-admin`), not a generic `admin`. When `auditd` traces an action, the executing account is recorded — a generic name makes the audit unusable.",{"title":66,"body":67},"Disable root SSH login","```bash\nsed -i 's\u002F^#\\?PermitRootLogin.*\u002FPermitRootLogin no\u002F' \u002Fetc\u002Fssh\u002Fsshd_config\ngrep PermitRootLogin \u002Fetc\u002Fssh\u002Fsshd_config\n```\n\nCaution: only reload `sshd` **after** verifying that your sudo user can connect and run `sudo su`. Otherwise you will lock yourself out of the server.\n\n**CIS reference**: CIS control 5.2.8 (Ensure SSH root login is disabled).",{"type":50,"title":69,"steps":70},"Block 3 — SSH key authentication",[71,74],{"title":72,"body":73},"Deploy the agency public key","```bash\nmkdir -p \u002Fhome\u002Fadminagency\u002F.ssh\nchmod 700 \u002Fhome\u002Fadminagency\u002F.ssh\necho \"\u003CAGENCY_PUBLIC_KEY>\" >> \u002Fhome\u002Fadminagency\u002F.ssh\u002Fauthorized_keys\nchmod 600 \u002Fhome\u002Fadminagency\u002F.ssh\u002Fauthorized_keys\nchown -R adminagency:adminagency \u002Fhome\u002Fadminagency\u002F.ssh\n```\n\n**Agency tip**: maintain a versioned public key repository (one file per technician, annual rotation). Every key deployed on a client VPS must be referenced in this repository — that is what allows you to revoke access when a team member leaves.",{"title":75,"body":76},"Disable password authentication","Once the key is verified (test from another terminal before confirming):\n\n```bash\nsed -i 's\u002F^#\\?PasswordAuthentication.*\u002FPasswordAuthentication no\u002F' \u002Fetc\u002Fssh\u002Fsshd_config\nsed -i 's\u002F^#\\?ChallengeResponseAuthentication.*\u002FChallengeResponseAuthentication no\u002F' \u002Fetc\u002Fssh\u002Fsshd_config\nsystemctl reload sshd\n```\n\n**CIS reference**: CIS control 5.2.11 (Ensure only approved MAC algorithms are used) and CIS 5.2.19 (Ensure SSH PasswordAuthentication is disabled).",{"type":50,"title":78,"steps":79},"Block 4 — UFW firewall",[80],{"title":81,"body":82},"Configure UFW with a default-deny policy","```bash\nufw default deny incoming\nufw default allow outgoing\nufw allow 22\u002Ftcp comment 'Agency SSH'\nufw allow 80\u002Ftcp comment 'HTTP'\nufw allow 443\u002Ftcp comment 'HTTPS'\nufw --force enable\nufw status verbose\n```\n\nOnly open ports actually used by the client project. If the client application does not use a direct mail port, do not open it.\n\nFor fail2ban installation and advanced UFW options, see the dedicated guides: \u003Ca href=\"\u002Fblog\u002Fproteger-vps-fail2ban\">Protecting a VPS with fail2ban\u003C\u002Fa> and \u003Ca href=\"\u002Fblog\u002Fpare-feu-ufw-vps\">UFW firewall on VPS\u003C\u002Fa>.\n\n**CIS reference**: CIS control 3.5.1 (Ensure a firewall package is installed).",{"type":50,"title":84,"steps":85},"Block 5 — fail2ban",[86],{"title":87,"body":88},"Enable fail2ban with the SSH jail","```bash\ncp \u002Fetc\u002Ffail2ban\u002Fjail.conf \u002Fetc\u002Ffail2ban\u002Fjail.local\n```\n\nEdit `\u002Fetc\u002Ffail2ban\u002Fjail.local` and adjust the `[sshd]` section:\n\n```bash\n[sshd]\nenabled = true\nmaxretry = 5\nfindtime = 600\nbantime = 3600\n```\n\n```bash\nsystemctl enable fail2ban\nsystemctl start fail2ban\nfail2ban-client status sshd\n```\n\nFor a client portfolio, consider \u003Ca href=\"\u002Fblog\u002Fsecuriser-vps-crowdsec\">CrowdSec\u003C\u002Fa> as a replacement or complement: its community blocklist pools intelligence from thousands of servers.",{"type":50,"title":90,"steps":91},"Block 6 — auditd: the traceability log",[92,95],{"title":93,"body":94},"Enable auditd and configure minimum rules","`auditd` is the component agencies most often forget — yet it is the one that provides defensible proof in the event of an incident.\n\n```bash\nsystemctl enable auditd\nsystemctl start auditd\n```\n\nCreate an agency rules file at `\u002Fetc\u002Faudit\u002Frules.d\u002Fagency.rules`:\n\n```bash\n# Trace all privilege escalations\n-w \u002Fetc\u002Fsudoers -p wa -k sudoers_changes\n-w \u002Fetc\u002Fsudoers.d\u002F -p wa -k sudoers_changes\n\n# Trace SSH connections\n-w \u002Fvar\u002Flog\u002Fauth.log -p wa -k auth_log\n\n# Trace changes to system configuration files\n-w \u002Fetc\u002Fssh\u002Fsshd_config -p wa -k sshd_config\n-w \u002Fetc\u002Fpasswd -p wa -k passwd_changes\n-w \u002Fetc\u002Fshadow -p wa -k shadow_changes\n\n# Trace commands executed as root\n-a always,exit -F arch=b64 -S execve -F euid=0 -k root_commands\n```\n\n```bash\naugenrules --load\nauditctl -l\n```\n\n**CIS reference**: CIS control 4.1.1 (Ensure auditing is enabled) and CIS 4.1.3 (Ensure events that modify date and time information are collected).",{"title":96,"body":97},"Export and retain auditd logs","`auditd` logs must be retained off the server to be defensible. Configure an export to your centralised system (rsyslog, Loki, or a simple daily `rsync` to agency storage):\n\n```bash\n# Example: rsyslog export to agency collector\necho ':programname, isequal, \"auditd\" @\u003CAGENCY_COLLECTOR_IP>:514' \\\n  >> \u002Fetc\u002Frsyslog.d\u002F99-auditd-remote.conf\nsystemctl restart rsyslog\n```\n\nRetain at least 90 days of logs. GDPR does not set a minimum retention period for security logs, but frameworks like **CIS Controls v8** (control 8.3) recommend at least 90 days on-site and 1 year in cold archive.",{"type":33,"title":99,"body":100},"Block 7 — Final verification and delivery record","Once the previous six blocks are complete, audit the server state before handing access to the client:\n\n```bash\n# Check active services\nsystemctl is-active ufw fail2ban auditd sshd\n\n# Confirm root cannot connect via SSH\ngrep PermitRootLogin \u002Fetc\u002Fssh\u002Fsshd_config\n\n# Check UFW rules\nufw status verbose\n\n# Check loaded auditd rules\nauditctl -l\n\n# Check recent logins\nlast -n 10\n```\n\nProduce a **dated and signed delivery record** (even by email) listing the measures applied, the versions of installed security packages, and the location of the log collector. This is the document your client signs and which constitutes contractual proof of the initial configuration.\n\nThe delivery record is not a formality: a client who suffers an intrusion two years after go-live will ask your agency to justify the server's state at delivery. Without this document, the burden of proof shifts.",{"type":102,"title":103,"headers":104,"rows":108},"comparison","Agency runbook vs. ad-hoc configuration: what changes",[105,106,107],"Criterion","Ad-hoc configuration","Standardised runbook",[109,113,117,121,125,129],[110,111,112],"Reproducibility","Depends on the technician present","Identical at every delivery",[114,115,116],"auditd traceability","Rarely enabled, variable config","Enabled and configured systematically",[118,119,120],"Proof in case of incident","No defensible evidence","Dated delivery record + centralised logs",[122,123,124],"Delegation to a junior","Risky (possible omissions)","Possible with the runbook as guide",[126,127,128],"SSH key rotation","Manual and forgotten","Written procedure, versioned repository",[130,131,132],"NIS2 \u002F GDPR compliance","Undocumented","Documented and reproducible",{"type":134,"body":135},"tip","**Monthly audit tip.** Once a month, re-run the final checks from Block 7 on each active client VPS and archive the output. A diff between two consecutive audits immediately reveals an unauthorised change: an extra open port, a stopped fail2ban service, a missing auditd rule. This audit takes less than five minutes per server when the commands are in a script.",{"type":33,"title":137,"body":138},"Troubleshooting: common errors when applying the runbook","**Error 1 — `sshd` refuses to start after modifying `sshd_config`**\nMessage: `sshd: \u002Fetc\u002Fssh\u002Fsshd_config line 42: unsupported option`\nCause: a deprecated or malformed directive. Verify with `sshd -t` before reloading the service. On Ubuntu 24.04, `ChallengeResponseAuthentication` is replaced by `KbdInteractiveAuthentication`.\n\n```bash\nsshd -t && systemctl reload sshd\n```\n\n**Error 2 — UFW blocks your own SSH connection**\nMessage: the SSH session freezes after `ufw enable`.\nCause: the SSH rule was not added before activation. Use the ServOrbit KVM console to access the server without SSH, then run `ufw allow 22\u002Ftcp` and `ufw reload`.\n\n**Error 3 — `auditd` starts but `auditctl -l` returns an empty list**\nMessage: `List of rules:` followed by nothing.\nCause: the rules file is not loaded. Verify your `.rules` file is in `\u002Fetc\u002Faudit\u002Frules.d\u002F` and run `augenrules --load`.\n\n**Error 4 — fail2ban does not ban despite multiple failed attempts**\nMessage: `fail2ban-client status sshd` shows `Currently banned: 0` after 10 attempts.\nCause: the SSH journal path has changed. On Debian 12 and Ubuntu 24.04 with journald, the fail2ban backend must be `systemd` in `jail.local`: `backend = systemd`.\n\n**Error 5 — `unattended-upgrades` restarts production services**\nCause: the default configuration automatically restarts services after updates. For a production client VPS, disable automatic reboot and schedule a maintenance window:\n\n```bash\n# In \u002Fetc\u002Fapt\u002Fapt.conf.d\u002F50unattended-upgrades\nUnattended-Upgrade::Automatic-Reboot \"false\";\n```",{"type":33,"title":140,"body":141},"Going further: bastioning and continuous monitoring","This checklist covers **level 1** of system hardening. For a client portfolio requiring a higher security level:\n\n- **SSH bastion**: centralise all access through a single hardened entry point — see \u003Ca href=\"\u002Fblog\u002Fheberger-bastion-host-vps\">Bastion Host on VPS\u003C\u002Fa>.\n- **CrowdSec**: behavioural detection and community blocklist as a complement or replacement for fail2ban — see \u003Ca href=\"\u002Fblog\u002Fsecuriser-vps-crowdsec\">Securing your VPS with CrowdSec\u003C\u002Fa>.\n- **Backups**: security configuration does not protect against data loss — see \u003Ca href=\"\u002Fblog\u002Fbackups-borgbackup-vps\">Backups with BorgBackup on VPS\u003C\u002Fa>.\n- **Application patches**: system hardening is useless if self-hosted applications are not maintained — see \u003Ca href=\"\u002Fblog\u002Froutine-correctifs-apps-self-hosted\">Patch routine for self-hosted apps\u003C\u002Fa>.\n- **SSL certificates**: HTTPS is required before any public exposure — see \u003Ca href=\"\u002Fblog\u002Fcertificats-ssl-lets-encrypt-vps\">SSL certificates with Let's Encrypt on VPS\u003C\u002Fa>.","ServOrbit delivers each VPS ready for this runbook","Immediate root SSH access and an included KVM console at delivery: your agency applies this runbook from the very first connection, for every client, without going through an intermediate access request to the hosting provider. Manage your entire client VPS portfolio from a centralised agency dashboard.","ServOrbit delivers each VPS","\u002Fsolutions\u002Fagences",[147,162,177],{"id":148,"slug":149,"slugs":150,"title":154,"excerpt":155,"readTime":156,"views":16,"isPinned":17,"publishedAt":157,"category":158,"categories":159,"featuredImage":27,"bgImage":28,"posterImage":161,"relatedSolution":27},116,"free-ssl-certificates-with-lets-encrypt-on-a-vps",{"fr":151,"en":149,"ar":152,"es":153},"certificats-ssl-lets-encrypt-vps","شهادات-ssl-مجانية-باستخدام-lets-encrypt-على-خادم-vps","certificados-ssl-gratis-con-lets-encrypt-en-un-vps","Free SSL Certificates with Let's Encrypt on a VPS","Deploy Let's Encrypt on your VPS: free HTTPS, automatic renewal, an A+ on SSL Labs with Nginx, Caddy or Traefik in Docker.",4,"2026-02-24T00:00:00+00:00",{"id":20,"name":21,"slug":22,"color":23,"icon":24},[160],{"id":20,"name":21,"slug":22,"color":23,"icon":24},"\u002Fblog\u002Fcovers\u002Fcertificats-ssl-lets-encrypt-vps-poster.svg",{"id":163,"slug":164,"slugs":165,"title":169,"excerpt":170,"readTime":171,"views":16,"isPinned":17,"publishedAt":172,"category":173,"categories":174,"featuredImage":27,"bgImage":28,"posterImage":176,"relatedSolution":27},278,"exposed-backoffice-on-vps-the-overlooked-attack-surfaces",{"fr":166,"en":164,"ar":167,"es":168},"backoffice-vps-surfaces-attaque-oubliees-2026","لوحة-إدارة-الخادم-الافتراضي-أسطح-الهجوم-المنسية","backoffice-expuesto-en-vps-superficies-de-ataque-olvidadas","Exposed backoffice on VPS: the overlooked attack surfaces","Four August 2026 CVEs share the same pattern: exposed backoffice, compromised account. Application authentication alone is not enough.",12,"2026-08-17T00:00:00+00:00",{"id":20,"name":21,"slug":22,"color":23,"icon":24},[175],{"id":20,"name":21,"slug":22,"color":23,"icon":24},"\u002Fblog\u002Fcovers\u002Fbackoffice-vps-surfaces-attaque-oubliees-2026-poster.svg",{"id":178,"slug":179,"slugs":180,"title":184,"excerpt":185,"readTime":156,"views":16,"isPinned":17,"publishedAt":186,"category":187,"categories":188,"featuredImage":27,"bgImage":28,"posterImage":190,"relatedSolution":27},114,"encrypted-vps-backups-with-borgbackup",{"fr":181,"en":179,"ar":182,"es":183},"backups-borgbackup-vps","نسخ-خادم-vps-الاحتياطية-المشفرة-باستخدام-borgbackup","copias-de-seguridad-vps-con-borgbackup","Encrypted VPS Backups with BorgBackup","Back up your VPS with BorgBackup: powerful deduplication, authenticated encryption and compression. A complete guide and Restic comparison.","2026-02-26T00:00:00+00:00",{"id":20,"name":21,"slug":22,"color":23,"icon":24},[189],{"id":20,"name":21,"slug":22,"color":23,"icon":24},"\u002Fblog\u002Fcovers\u002Fbackups-borgbackup-vps-poster.svg",1788100067541]