[{"data":1,"prerenderedAt":233},["ShallowReactive",2],{"seo-verification":3,"blog-test-client-vps-backup-restore-agency-procedure-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-test-client-vps-backup-restore-agency-procedure-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":183,"ctaBody":184,"ctaButton":185,"ctaUrl":186,"relatedPosts":187},523,"test-client-vps-backup-restore-agency-procedure",{"fr":12,"en":10,"ar":13,"es":14},"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.",11,0,false,"2026-10-28T00:00:00+00:00","2026-10-29T03:10:23+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\u002Ftester-restauration-sauvegarde-vps-client-agence-procedure-poster.svg","A backup that exists is not a backup that can be read back, and the difference shows up on the day of an incident, in front of the client. This guide is for agencies that run a portfolio of sites and must answer \"prove you can restore\". It describes a complete, manual, quarterly exercise on a disposable test VPS: restore from the real repository, time the RTO, calculate the observed RPO, then hand the client a dated log. The automatic sentinel-file check is covered elsewhere; here, we produce the proof.",[35,39,49,52,83,86,126,157,167,170,174,177,180],{"type":36,"title":37,"body":38},"h2","This test is not the automatic check: what it adds","The guide on the 3-2-1 strategy with Restic and S3 describes an automatic check: a sentinel file restored every week, which raises an alert when the backup chain breaks. It is useful and worth keeping. But it answers \"can the repository be read?\", not \"does the client's site come back, and how fast?\". Restoring a file of a few bytes tells you nothing about a database, uploaded files, the expected PHP version or missing secrets.\n\nThe exercise in this guide restores an entire site, by hand, on a new machine, and produces three measurements: a duration, the age of the data and a list of anomalies. The two mechanisms do not compete. The automatic check detects the failure every week; the quarterly exercise proves the recovery, with a signature and a date. That is the proof a client, a tender or an audit ends up asking for.\n\nNor should it be confused with the restore check in the monthly security audit checklist for a client VPS: that one verifies each month that a file or a database restores; the quarterly exercise in this guide brings a whole site back up, stopwatch in hand.",{"type":40,"title":41,"items":42},"ul","What the exercise proves that the backup alone does not",[43,44,45,46,47,48],"**The repository can be read without the original server** — the restore starts from the remote repository, with secrets kept elsewhere, never from the site's disk.","**The site really starts again** — the home page, the admin login and the latest content in the database respond on the new machine.","**The RTO is measured, not assumed** — an observed duration replaces the estimate \"about an hour\".","**The RPO keeps its promise** — the gap between the simulated incident and the restored snapshot is compared with what the contract states.","**The access sits in the right hands** — the test reveals who really holds the repository password and keys.","**A proof exists** — a dated, signed log handed to the client works as a sales argument and as protection in a dispute.",{"type":36,"title":50,"body":51},"Preparing the test: scope, disposable machine, effort","Pick one site per client per quarter, alternating profiles: a site backed by a database, another with large uploaded files, a third with scheduled tasks. Before you start, gather three things outside the site's server: access to the repository, the password or key that opens it, and the list of the application's secrets.\n\nThen rent a disposable test VPS with the same system as production, and plan to destroy it at the end of the session. For the effort, count as an editorial order of magnitude half a day per quarter for a typical site, more for a large repository, less once the procedure is routine. Write down the start time before the first command, never after.",{"type":53,"title":54,"steps":55},"steps","The procedure in nine steps",[56,59,62,65,68,71,74,77,80],{"title":57,"body":58},"Set the simulated incident","Write down the exact time of the simulated incident, for example the last known write on the site, and the scope to restore: files, database, configuration. This time feeds the RPO calculation.",{"title":60,"body":61},"Create the test VPS","Create a new machine with the same operating system as production. No site file reaches it from the original disk. Write down the start time: it starts the RTO stopwatch.",{"title":63,"body":64},"Install the tool and open the repository","Install only the backup tool and the site's stack (web server, PHP, database). Fetch the credentials from your password vault, never from the failed server. `restic -r \u003Crepository> snapshots` must list the restore points.",{"title":66,"body":67},"Choose the snapshot","Pick the last snapshot before the simulated incident and note its identifier and timestamp. It fixes the observed RPO.",{"title":69,"body":70},"Restore the files","`restic -r \u003Crepository> restore \u003Cid> --target \u002Fsrv\u002Frestore`\nThen move the content to the web directory. With Borg, first move into the target folder, because extraction writes to the current directory: `cd \u002Fsrv\u002Frestore && borg extract \u003Crepository>::\u003Carchive>`.",{"title":72,"body":73},"Restore the database","`pg_restore --create --dbname=postgres backup.dump`\nFor a plain-text dump, `psql -f backup.sql`. Then count the rows of a witness table (`SELECT count(*) FROM orders;`) and compare with the value read in production before the test.",{"title":75,"body":76},"Rebuild the configuration","Put back the `.env` file, the secrets, the vhost and the scheduled tasks from the vault, then align the PHP and database versions with production.",{"title":78,"body":79},"Check the application","Open the home page, log in to the admin area and find the latest order or article in the database. Without touching DNS: `curl -k --resolve your-domain.com:443:\u003CTEST_VPS_IP> https:\u002F\u002Fyour-domain.com\u002F`.",{"title":81,"body":82},"Stop the stopwatch and destroy the machine","Stop at the first successful application request, not when the restore command finishes. Calculate the RTO and the RPO, fill in the log, then destroy the test VPS.",{"type":36,"title":84,"body":85},"The stopwatch: observed RTO and RPO","The observed RTO is the time the verified restore ends minus the time the test started. The observed RPO is the gap between the time of the simulated incident and the timestamp of the restored snapshot. Take a fictional example: simulated incident at 14:00, last snapshot taken at 03:00 the same day, so 11 hours of data lost. If the contract promises 24 hours, it complies; if it promises 4, it does not, and the log must say so as it is.\n\nAn RTO measured in a test remains an optimistic floor: new machine, nobody waiting, no pressure. It still beats a back-of-the-envelope calculation, especially with a large repository: on a modest connection, download time alone makes a theoretical RTO unrealistic. Measure the real throughput during the restore and note it in the log.",{"type":87,"title":88,"headers":89,"rows":93},"comparison","The test log: fields to fill in",[90,91,92],"Field","What to record","Example",[94,98,102,106,110,114,118,122],[95,96,97],"Date and site","Day of the test and the client site restored","DD\u002FMM\u002FYYYY, demo site",[99,100,101],"Tool and snapshot","Backup tool, snapshot identifier and timestamp","Restic, short identifier, full timestamp",[103,104,105],"Duration and RTO","Start time, verified end time, observed duration","Start 09:00, end 10:40, RTO 1 h 40",[107,108,109],"Observed RPO","Gap between simulated incident and snapshot, compared with the target","11 h observed for 24 h promised",[111,112,113],"Anomalies","Everything that blocked or slowed the recovery","Uploads folder missing from the scope",[115,116,117],"Fix and deadline","Action, owner and completion date","Add the folder to the repository before the next test",[119,120,121],"Signatory","Person who attests to the test","Name, role, signature",[123,124,125],"Out of scope","What was not tested","Email, DNS, certificates, third-party services",{"type":87,"title":127,"headers":128,"rows":132},"Reference commands by tool",[129,130,131],"Tool","List restore points","Restore and check",[133,137,141,145,149,153],[134,135,136],"Restic","`restic -r \u003Crepository> snapshots`","`restic -r \u003Crepository> restore \u003Cid> --target \u002Fsrv\u002Frestore`",[138,139,140],"Restic, repository integrity","`restic -r \u003Crepository> check`","`check` verifies the structure; `--read-data` rereads the whole repository, `--read-data-subset=10%` a random share",[142,143,144],"Borg","`borg list \u003Crepository>`, then `borg list \u003Crepository>::\u003Carchive>`","`borg extract --list \u003Crepository>::\u003Carchive>` from the target folder; `--dry-run` reads and verifies without writing",[146,147,148],"PostgreSQL, custom dump","`pg_restore --list backup.dump`","`pg_restore --create --dbname=postgres backup.dump`, then count a witness table",[150,151,152],"PostgreSQL, plain dump","Check the file size and date","`psql -f backup.sql`, then count a witness table",[154,155,156],"Uploaded files","Compare the file count in the repository with production","`find \u002Fsrv\u002Frestore -type f | wc -l`, then open three files at random",{"type":40,"title":158,"items":159},"Restore pitfalls, with their symptom",[160,161,162,163,164,165,166],"**Repository key stored on the failed server** — the new machine cannot open the repository and shows `wrong password or no key found`; keep the key in a separate vault, with two holders.","**Database restored, uploaded files missing** — the site displays but images and attachments return 404; the scope covered only the database or only the code.","**Different PHP or database version** — blank page, syntax or migration error; record each site's versions in the log.","**Secrets and `.env` not backed up** — the application starts but no longer reaches the database, the mail server or third-party APIs.","**Repository too large for the bandwidth** — the theoretical RTO looks fine, the real RTO exceeds the promise; measure throughput before promising.","**Truncated dump** — the row count of the witness table does not match production; rerun the backup and check its size.","**Scheduled tasks not recreated** — the site responds but no longer sends emails or reminders; inventory the cron jobs before the test.",{"type":36,"title":168,"body":169},"Troubleshooting: errors seen during an exercise","**`Fatal: wrong password or no key found`** — Restic finds no key that opens with the password supplied. Frequent causes to rule out one by one: a password with special characters altered by the shell, a password read from standard input, an S3 repository URL in the wrong style, a damaged key file. Try `--password-file` or the `RESTIC_PASSWORD` variable, check the repository URL, then `restic key list`. If the password is truly lost, the repository data is lost with it: record it as a critical anomaly.\n\n**No recent restore point** — `restic snapshots` lists nothing from the past week: the backup job stops silently. Fix the timer and add an alert.\n\n**`pg_restore` ends with ignored errors** — by default it continues and prints a count at the end. Rerun with `--exit-on-error` to stop at the first error, and read it before declaring the test a success.\n\n**The files are there but the site returns 403** — restoring as root left the files with the wrong owner. Give them back to the web server user.",{"type":171,"title":172,"body":173},"tip","The repository password never lives alone on the server","Keep it in a team vault, with a sealed copy held by a second person in charge. The exercise starts by opening the repository from that vault: if someone has to log in to the site's server to find the password, the test has already failed, and that is the most useful anomaly it can reveal.",{"type":36,"title":175,"body":176},"The log handed to the client: one page, and what was not tested","The log fits on one page: a header with client, site and date; the table of eight fields; a one-sentence conclusion, compliant or not with the RPO and RTO targets; a dated corrective plan; a signature. Reserve a final box \"Not tested in this exercise\": mailboxes and deliverability, DNS and delegation, TLS certificates, third-party services such as payment or a CRM, and any other site on the account.\n\nA log that does not state its limits reads as \"everything is backed up\", and that is a promise nobody can keep. Keep the logs of every quarter: one test proves one day, a series proves a practice. Also record each site's PHP version, as in the guide on the version inventory of a client portfolio: it is the most frequent trap when you replay a restore.",{"type":36,"title":178,"body":179},"On the contract side: what the backup clause must name","A useful clause names seven points: the scope (files, databases, configuration), the frequency, the retention, the RPO and RTO targets, the frequency and proof of tests, the liability if the restore fails, and the person who holds the repository access. This is not legal advice: have the text reviewed by a lawyer. And never promise what the underlying infrastructure does not guarantee.\n\nOn that point, ServOrbit.com backups are weekly on the entry level, daily on Pro and on all reseller hosting offers. The floor RPO follows from that frequency: up to seven days with a weekly backup, up to one day with a daily one. An RPO under one day therefore requires the agency's own application backup, in addition. As for restore time, no commitment follows from a frequency: it is measured, with the exercise above.",{"type":36,"title":181,"body":182},"Making the test billable: a selling point, not a burden","The objection is familiar: the client does not ask for it, and the time is not billed. Two answers. Build a line \"quarterly restore test, log delivered\" into the maintenance plan, or bill the half day separately. And treat the log as a deliverable: after an incident it shows what had been tested and fixed; during a sale it answers \"prove it\" before the question is asked.\n\nTo keep the pace across a portfolio, plan a rotation: one site per client per quarter, with the calendar set at the start of the year. The test VPS is rented and destroyed on demand; the terms are on the offer page.","A portfolio of sites, proof to deliver","An agency that must prove its restores needs one place for its portfolio: domains, hosting and disposable trial VPS. The ServOrbit.com agency space centralizes services and expirations: you keep the client relationship, we run the infrastructure.","Discover the agency offer","\u002Fsolutions\u002Fagences",[188,203,218],{"id":189,"slug":190,"slugs":191,"title":195,"excerpt":196,"readTime":17,"views":18,"isPinned":19,"publishedAt":197,"updatedAt":198,"category":199,"categories":200,"featuredImage":30,"bgImage":31,"posterImage":202,"relatedSolution":30},347,"restic-s3-3-2-1-backup-strategy-vps",{"fr":192,"en":190,"ar":193,"es":194},"backup-vps-restic-s3-3-2-1","restic-s3-3-2-1-backup-strategy-vps-ar","estrategia-3-2-1-backup-vps-restic-s3","3-2-1 Backup Strategy for Your VPS with Restic and S3","Build a complete 3-2-1 strategy on your VPS: Restic to Backblaze B2 or Cloudflare R2, systemd timer, retention policy and automated restore test.","2026-09-10T00:00:00+00:00","2026-10-20T23:18:06+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[201],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fbackup-vps-restic-s3-3-2-1-poster.svg",{"id":204,"slug":205,"slugs":206,"title":210,"excerpt":211,"readTime":212,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":213,"category":214,"categories":215,"featuredImage":30,"bgImage":31,"posterImage":217,"relatedSolution":30},521,"monthly-security-audit-checklist-client-vps-agency",{"fr":207,"en":205,"ar":208,"es":209},"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,"2026-10-29T03:10:22+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[216],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fchecklist-audit-securite-mensuel-vps-clients-agence-poster.svg",{"id":219,"slug":220,"slugs":221,"title":225,"excerpt":226,"readTime":17,"views":18,"isPinned":19,"publishedAt":227,"updatedAt":228,"category":229,"categories":230,"featuredImage":30,"bgImage":31,"posterImage":232,"relatedSolution":30},508,"php-version-inventory-for-client-sites-an-agency-method",{"fr":222,"en":220,"ar":223,"es":224},"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},[231],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Finventaire-versions-php-parc-sites-clients-agence-poster.svg",1793251391008]