[{"data":1,"prerenderedAt":219},["ShallowReactive",2],{"seo-verification":3,"blog-monthly-security-audit-checklist-client-vps-agency-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-monthly-security-audit-checklist-client-vps-agency-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":30,"intro":33,"sections":34,"ctaTitle":168,"ctaBody":169,"ctaButton":170,"ctaUrl":171,"relatedPosts":172},521,"monthly-security-audit-checklist-client-vps-agency",{"fr":12,"en":10,"ar":13,"es":14},"checklist-audit-securite-mensuel-vps-clients-agence","قائمة-تدقيق-أمان-vps-شهرية-للعملاء-للوكالات","auditoria-seguridad-mensual-vps-clientes-agencia-checklist","Monthly client VPS security audit: a 45-minute checklist","Seven checks to run every month on a client VPS: updates, kernel, SSH accounts, ports, certificates, backups, logs. Includes a dated one-page report.",10,0,false,"2026-10-28T00:00:00+00:00","2026-10-29T03:10:22+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},8,"Security & Monitoring","securite-monitoring","bg-rose-500\u002F10 text-rose-400","security",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fchecklist-audit-securite-mensuel-vps-clients-agence-poster.svg","A client does not ask whether their VPS is secure, they ask how long you have known. An agency without a routine can answer neither on the day a vulnerability lands nor at contract renewal. This checklist runs seven read-only checks per VPS in 45 minutes: pending updates, kernel, SSH accounts and keys, open ports, certificates, restored backups, authentication logs. It ends with a dated one-page report that you hand to the client and compare from one month to the next.",[35,39,42,52,77,111,114,117,138,142,150,153,156,165],{"type":36,"title":37,"body":38},"h2","Verify a state, do not rebuild it","Initial VPS hardening happens once, at delivery: SSH keys, firewall, fail2ban, automatic updates. Our hardening checklist already covers it. Here we assume all of that exists and ask whether it still holds. A package left pending, an account created for a contractor and never removed, a port opened for a test, a certificate whose renewal fails silently: none of it shows unless you look. The monthly audit is therefore a verification routine, not a configuration one. Each check produces an output that you archive, and a green, orange or red status in the client's report. A deviation is recorded, never fixed without agreement.",{"type":36,"title":40,"body":41},"Set the scope before the first audit","Before the first command, write down who is responsible for what. Does the VPS belong to the client or to the agency? Who holds the root account, who receives alerts, who decides on a reboot? Without answers, the first deviation you find becomes a dispute: was the agency allowed to fix it, had the client been told? Take five points into your contract or order form: the VPS covered, the audit frequency, the read-only access granted, the response time for a red deviation, and the list of actions the agency may take alone, such as applying a security update, as opposed to those that need client approval, such as a reboot or an account removal.",{"type":43,"title":44,"items":45},"ul","To prepare once, before auditing",[46,47,48,49,50,51],"**A dedicated audit account** — a named user with `sudo` limited to reading logs and inspecting the network, rather than a shared root.","**An expected list per VPS** — ports that should listen, authorized accounts, domains served, backup tool and repository. Without a reference, a deviation cannot be told apart from normal behaviour.","**A read-only collection script** — it chains the commands of the checklist and writes everything to a dated file, so each command is typed only once.","**An archive folder per client** — one subfolder per month, kept outside the audited VPS, so months can be compared.","**A report template** — the same layout for every client, filled in from the collected outputs.","**A calendar** — a fixed day of the month per client, noted in the team agenda, otherwise the audit is skipped in the first busy month.",{"type":53,"title":54,"steps":55},"steps","The seven checks, with their time budget",[56,59,62,65,68,71,74],{"title":57,"body":58},"Pending updates (6 min)","`sudo apt update`\n`apt list --upgradable 2>\u002Fdev\u002Fnull`\n`apt list --upgradable 2>\u002Fdev\u002Fnull | grep -i security`\nIsolate packages whose origin ends in `-security`: they go first. The others go through human validation, because a major version jump can break an application. On AlmaLinux or RHEL, `sudo dnf check-update --security` plays the same role. Even with automatic updates enabled, this check shows what remains blocked.",{"title":60,"body":61},"Kernel and pending reboot (4 min)","`uname -r`\n`ls \u002Fboot\u002Fvmlinuz-*`\n`ls \u002Fvar\u002Frun\u002Freboot-required`\n`sudo needrestart -b -r l`\nIf the newest installed kernel differs from `uname -r`, or if `\u002Fvar\u002Frun\u002Freboot-required` exists, a reboot is due. In the needrestart output, the `NEEDRESTART-KSTA` line tells whether the running kernel is current, and the list shows services still using old libraries. The reboot is never done alone: it is scheduled with the client.",{"title":63,"body":64},"Accounts and SSH keys (8 min)","`awk -F: '$3>=1000' \u002Fetc\u002Fpasswd`\n`getent group sudo`\n`sudo ssh-keygen -lf \u002Fhome\u002F\u003Caccount>\u002F.ssh\u002Fauthorized_keys`\n`lastlog | grep -v 'Never logged in'`\n`last -n 20`\nEvery human account must match a person known to the client or the agency. Every key fingerprint must belong to someone still working on the project. An account that has not logged in for months, or an unknown key, turns orange and goes to the client for validation.",{"title":66,"body":67},"Open ports (5 min)","`sudo ss -tlnp`\n`sudo ss -ulnp`\n`sudo ufw status verbose`\nCompare the result with the list expected for this VPS. A database listening on all interfaces instead of the loopback, a forgotten test port, an unknown service: each deviation is recorded with the process that opens it, without closing it immediately, because a service may depend on that port.",{"title":69,"body":70},"Certificates (4 min)","`openssl s_client -connect your-domain.com:443 -servername your-domain.com \u003C\u002Fdev\u002Fnull 2>\u002Fdev\u002Fnull | openssl x509 -noout -enddate`\nRead the expiry date on the service actually exposed, not just the presence of a renewal timer: an active timer can fail every night. If the domain goes through a CDN, this command reads the CDN certificate. For the origin, replace the host in `-connect` with the VPS IP address and keep `-servername`.",{"title":72,"body":73},"Restored backups (10 min)","`restic snapshots`\n`restic restore latest --target \u002Ftmp\u002Frestore-test --include \u002Fetc\u002Fnginx`\nNote the date of the latest restore point, then actually restore a file or a database into a temporary directory and open it. A backup that was never restored is not proof, it is a hypothesis. Delete the temporary directory afterwards. If the client uses another tool, the logic is the same: list the points, partial restore, check the content.",{"title":75,"body":76},"Authentication logs (8 min)","`sudo journalctl -u ssh --since '30 days ago' --no-pager | grep -c 'Failed password'`\n`sudo journalctl -u ssh --since '30 days ago' --no-pager | grep 'Accepted'`\n`sudo journalctl _COMM=sudo --since '30 days ago' --no-pager`\nCount the failures, list the successful logins and look for those from an unknown address. Review `sudo` usage. On RHEL and derivatives, the unit is called `sshd`, not `ssh`.",{"type":78,"title":79,"headers":80,"rows":84},"comparison","The 45-minute budget per VPS",[81,82,83],"Check","Key command","Time",[85,89,93,97,101,104,108],[86,87,88],"Pending updates","`apt list --upgradable`","6 min",[90,91,92],"Kernel and reboot","`needrestart -b -r l`","4 min",[94,95,96],"Accounts and SSH keys","`ssh-keygen -lf authorized_keys`","8 min",[98,99,100],"Open ports","`ss -tlnp`","5 min",[102,103,92],"Certificates","`openssl s_client`",[105,106,107],"Restored backups","`restic restore`","10 min",[109,110,96],"Authentication logs","`journalctl -u ssh`",{"type":36,"title":112,"body":113},"A collection script instead of seven manual sessions","Most of the 45 minutes is reading, not typing, provided you do not retype the commands. Write an `audit-vps` script that runs the commands of checks one to seven and redirects each output to a file named after the client and the date, for example `~\u002Faudits\u002Fclient-a\u002FYYYY-MM\u002Fraw-output.txt`. It contains only read commands: no `apt upgrade`, no `systemctl restart`, no `rm`. Run it over SSH from your workstation, fetch the file, then read it calmly. The backup restore stays the only manual step, because it requires judging whether the restored content is consistent.",{"type":36,"title":115,"body":116},"Archive and compare: that is where drift shows","A single audit gives a snapshot, two consecutive audits give a trend. Keep the raw output of each month, then compare it with the previous one using `diff -u previous-audit.txt current-audit.txt`. A port that appears, an extra account, a number of failed logins multiplied by ten, a restore point that no longer moves: all these signals stand out in a few lines of difference, while they are invisible in an output read alone. Also archive the report handed to the client. The day the client asks since when an account existed or when a fix was applied, the answer is a dated file, not a memory.",{"type":53,"title":118,"steps":119},"The one-page report handed to the client",[120,123,126,129,132,135],{"title":121,"body":122},"The header","Client name, VPS identifier, IP address, audit date, name of the person who ran it.",{"title":124,"body":125},"The table of the seven checks","One line per check with a status: green if nothing to report, orange if a deviation needs a client decision, red if urgent action is needed.",{"title":127,"body":128},"The deviations found","Each deviation in one factual sentence, with the evidence: the output line, the port, the account concerned.",{"title":130,"body":131},"The actions taken","What the agency applied alone, within the agreed scope, for example a security update.",{"title":133,"body":134},"The actions for the client to approve","Reboot, account removal, closing a port, with the risk of doing nothing.",{"title":136,"body":137},"The next due date","The date of the next audit and, for each orange or red deviation, a deadline for handling it.",{"type":139,"title":140,"body":141},"tip","Record the deviation, do not fix it on the spot","The reflex to close the port or delete the suspicious account during the audit is the most expensive one: a client service goes down, and the agency decided it alone. The role of the audit is to make the deviation visible and dated. The fix follows the approval path agreed at the start, even for what looks obvious.",{"type":43,"title":143,"items":144},"When an output does not say what it seems to say",[145,146,147,148,149],"**`needrestart` not found** — the package is not installed by default everywhere. Install it once with the client's agreement, or compare `uname -r` and the kernels in `\u002Fboot` by hand.","**No SSH failures in the logs** — check the unit name before concluding. Depending on the distribution, authentication is logged under `ssh`, `sshd` or, on recent OpenSSH versions, `sshd-session`. Try `sudo journalctl _COMM=sshd-session --since '30 days ago'`.","**`ss -tlnp` does not show processes** — without `sudo`, the process column stays empty for other users' services.","**A valid certificate while the site shows an error** — you read the one from a CDN or another vhost. Point at the VPS address and pass the right `-servername`.","**`restic` asks for a password** — the repository is encrypted. Get the secret from the client before the audit, not during it, otherwise the check is skipped.",{"type":36,"title":151,"body":152},"The time objection: 45 minutes per client, every month","Twenty clients make fifteen hours a month, and the objection is fair. Three levers reduce it. First, time is measured per VPS, not per client: a client with a single server costs 45 minutes, and less from the second month, because the expected references are in place. Second, the script collects everything, you only read, and the report is filled in from a template. Finally, compare with the cost of an undetected incident: a forgotten access or an unusable backup is discovered on the day of the outage, with an unhappy client and a recovery bill. The routine costs less than a single avoidable incident.",{"type":36,"title":154,"body":155},"When the portfolio grows","At ten VPS, the checklist fits in a day. At fifty, the difficulty becomes organisational: knowing which client has what, which due dates fall this month, who has been audited. The ServOrbit.com agency space gathers each client's services and due dates in a single interface, which avoids maintaining a parallel spreadsheet. If the agency prefers not to carry the system base itself, the VPS administration option exists and is looked at separately. This guide is provided as is, without support: running the audit and the responsibility towards the client remain yours.",{"type":43,"title":157,"items":158},"Going further",[159,160,161,162,163,164],"**Set up the base** — \u002Fblog\u002Flinux-hardening-vps-checklist describes the initial hardening that this audit verifies.","**Automate fixes** — \u002Fblog\u002Fsecurite-vps-mises-a-jour-automatiques-debian-ubuntu explains unattended-upgrades, whose leftovers the first check measures.","**Back up properly** — \u002Fblog\u002Fbackup-vps-restic-s3-3-2-1 covers setting up Restic, whose restore the sixth check verifies.","**Monitor continuously** — \u002Fblog\u002Falertes-disque-ram-vps-monitoring-proactif complements the monthly audit with alerts between two passes.","**Inventory PHP versions** — \u002Fblog\u002Finventaire-versions-php-parc-sites-clients-agence applies the same discipline to the site fleet.","**Respond to a vulnerability** — the fix guides in the Security and monitoring category of the blog show what an up-to-date inventory lets you do on day one.",{"type":36,"title":166,"body":167},"The official documentation","apt options: https:\u002F\u002Fmanpages.debian.org\u002Fstable\u002Fapt\u002Fapt.8.en.html\n\nneedrestart project: https:\u002F\u002Fgithub.com\u002Fliske\u002Fneedrestart\n\nAutomatic updates on Debian: https:\u002F\u002Fwiki.debian.org\u002FUnattendedUpgrades\n\nss command: https:\u002F\u002Fman7.org\u002Flinux\u002Fman-pages\u002Fman8\u002Fss.8.html\n\nopenssl s_client command: https:\u002F\u002Fdocs.openssl.org\u002Fmaster\u002Fman1\u002Fopenssl-s_client\u002F\n\njournalctl command: https:\u002F\u002Fwww.freedesktop.org\u002Fsoftware\u002Fsystemd\u002Fman\u002Flatest\u002Fjournalctl.html\n\nsshd daemon: https:\u002F\u002Fman.openbsd.org\u002Fsshd.8\n\nlast command: https:\u002F\u002Fman7.org\u002Flinux\u002Fman-pages\u002Fman1\u002Flast.1.html","A portfolio of VPS readable from one place","Auditing a fleet by hand becomes unmanageable as the portfolio grows. The ServOrbit.com agency space gathers each client's services and due dates in a single interface, and the VPS administration option lets you hand over the system base.","Discover the agency offer","\u002Fsolutions\u002Fagences",[173,190,205],{"id":174,"slug":175,"slugs":176,"title":180,"excerpt":181,"readTime":182,"views":183,"isPinned":19,"publishedAt":184,"updatedAt":185,"category":186,"categories":187,"featuredImage":30,"bgImage":31,"posterImage":189,"relatedSolution":30},317,"linux-vps-hardening-checklist-for-agencies",{"fr":177,"en":175,"ar":178,"es":179},"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,1,"2026-08-30T00:00:00+00:00","2026-09-07T11:26:10+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[188],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Flinux-hardening-vps-checklist-poster.svg",{"id":191,"slug":192,"slugs":193,"title":197,"excerpt":198,"readTime":182,"views":18,"isPinned":19,"publishedAt":199,"updatedAt":200,"category":201,"categories":202,"featuredImage":30,"bgImage":31,"posterImage":204,"relatedSolution":30},508,"php-version-inventory-for-client-sites-an-agency-method",{"fr":194,"en":192,"ar":195,"es":196},"inventaire-versions-php-parc-sites-clients-agence","جرد-إصدارات-php-لمواقع-العملاء-منهج-للوكالات","inventario-de-versiones-php-de-sitios-cliente-metodo-de-agencia","PHP version inventory for client sites: an agency method","Build a register of the PHP version served by every client site across several hosts: access tiers, batch scripts, priority batches, client message, dated proof.","2026-10-27T00:00:00+00:00","2026-10-27T23:58:39+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[203],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Finventaire-versions-php-parc-sites-clients-agence-poster.svg",{"id":206,"slug":207,"slugs":208,"title":212,"excerpt":213,"readTime":182,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":214,"category":215,"categories":216,"featuredImage":30,"bgImage":31,"posterImage":218,"relatedSolution":30},523,"test-client-vps-backup-restore-agency-procedure",{"fr":209,"en":207,"ar":210,"es":211},"tester-restauration-sauvegarde-vps-client-agence-procedure","اختبار-استعادة-نسخة-احتياطية-vps-عميل-وكالة-إجراء","probar-restauracion-copia-seguridad-vps-cliente-agencia-procedimiento","Testing a client backup restore: an agency procedure","A quarterly procedure to restore a client site on a disposable VPS, measure the actual RTO and RPO, and hand the client a dated restore test log.","2026-10-29T03:10:23+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[217],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Ftester-restauration-sauvegarde-vps-client-agence-procedure-poster.svg",1793251360500]