<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged backup</title>
<link>https://coderlegion.com/tag/backup</link>
<description>Powered by Question2Answer</description>
<item>
<title>rsync's dangerous flags don't fail. They do a different job and exit 0.</title>
<link>https://coderlegion.com/28025/rsyncs-dangerous-flags-dont-fail-they-do-a-different-job-and-exit-0</link>
<description>&lt;p&gt;The trap with rsync is that its dangerous flag combinations don't fail — they complete a different operation than the one you intended, and exit 0. &lt;code&gt;--delete&lt;/code&gt; makes the destination match the source, so a mistyped or freshly moved source directory means rsync removes everything at the destination and reports success. Your cron log shows a clean run while the backup empties itself. A trailing slash changes the meaning too: &lt;code&gt;/data/&lt;/code&gt; syncs the directory's contents, while &lt;code&gt;/data&lt;/code&gt; copies the directory itself into the destination — and on a mirror job, that difference decides what gets compared and what gets deleted.&lt;/p&gt;
&lt;p&gt;The defense is previewing every destructive sync before running it live:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;rsync -av --delete --dry-run /srv/www/ user@backup:/srv/backup/www/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read the &lt;code&gt;deleting …&lt;/code&gt; lines it prints; only when that list matches your expectations do you remove &lt;code&gt;--dry-run&lt;/code&gt;. Note also that excludes take one pattern per flag — &lt;code&gt;--exclude='*.log' --exclude='.git'&lt;/code&gt; — because a comma-separated list inside a single flag silently matches nothing.&lt;/p&gt;
&lt;p&gt;If you'd rather compose the command with those guardrails enforced — a red warning when &lt;code&gt;--delete&lt;/code&gt; is enabled without a dry run, per-pattern quoted excludes, and a live preview of the finished command — I built a &lt;a rel=&quot;nofollow&quot; href=&quot;https://bashsnippets.xyz/tools/rsync-command-builder&quot;&gt;visual rsync command builder with delete-flag guardrails&lt;/a&gt; that runs entirely in the browser.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/28025/rsyncs-dangerous-flags-dont-fail-they-do-a-different-job-and-exit-0</guid>
<pubDate>Tue, 20 Oct 2026 13:00:00 +0000</pubDate>
</item>
<item>
<title>How to Back Up and Restore Self-Hosted n8n</title>
<link>https://coderlegion.com/25673/how-to-back-up-and-restore-self-hosted-n8n</link>
<description>
&lt;p&gt;
        A recoverable self-hosted n8n backup has four core parts: the database, the original encryption key, the deployment configuration and secrets, and any binary-data storage your executions still need. Back up the persistent &lt;code&gt;.n8n&lt;/code&gt; volume even when PostgreSQL stores the main database. n8n documents that this directory can still contain the encryption key, logs, and source-control assets.
      &lt;/p&gt;

      &lt;div class=&quot;article-callout&quot;&gt;
        &lt;p&gt;&lt;strong&gt;Partner disclosure.&lt;/strong&gt; This guide includes a partner link to &lt;a href=&quot;https://n8n.partnerlinks.io/6mg2xng7s1m6&quot; target=&quot;_blank&quot; rel=&quot;sponsored noopener nofollow&quot;&gt;n8n Cloud&lt;/a&gt;. If you sign up through it, I may earn a commission at no extra cost to you.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class=&quot;article-callout&quot;&gt;
        &lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; workflow JSON files alone are not enough. They do not recreate the complete instance state, and encrypted credentials are unusable without the key that encrypted them.&lt;/p&gt;
      &lt;/div&gt;

      &lt;h2 id=&quot;what-must-be-in-the-backup&quot;&gt;What must be in the backup&lt;/h2&gt;
      &lt;div class=&quot;article-table-wrap&quot;&gt;
        &lt;table class=&quot;article-table&quot;&gt;
          &lt;thead&gt;
            &lt;tr&gt;
              &lt;th&gt;Asset&lt;/th&gt;
              &lt;th&gt;Why it matters&lt;/th&gt;
              &lt;th&gt;Typical location&lt;/th&gt;
            &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;
            &lt;tr&gt;
              &lt;td&gt;Database&lt;/td&gt;
              &lt;td&gt;Workflows, encrypted credentials, users, projects, settings, and retained execution data&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;~/.n8n/database.sqlite&lt;/code&gt; or PostgreSQL&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;Encryption key&lt;/td&gt;
              &lt;td&gt;Decrypts the credentials stored in the database&lt;/td&gt;
              &lt;td&gt;&lt;code&gt;~/.n8n&lt;/code&gt; settings or &lt;code&gt;N8N_ENCRYPTION_KEY&lt;/code&gt;&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;Deployment config&lt;/td&gt;
              &lt;td&gt;Restores database connection, public URL, proxy, timezone, pruning, and execution behavior&lt;/td&gt;
              &lt;td&gt;Compose file, environment settings, secret references, proxy config&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;Binary data&lt;/td&gt;
              &lt;td&gt;Restores retained files handled by executions when filesystem or external storage is used&lt;/td&gt;
              &lt;td&gt;Persistent filesystem, database, or configured external store&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;Custom and community nodes&lt;/td&gt;
              &lt;td&gt;Allows restored workflows to load the same node types and versions&lt;/td&gt;
              &lt;td&gt;Package list, custom-node directory, container image, or build manifest&lt;/td&gt;
            &lt;/tr&gt;
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/div&gt;
      &lt;p&gt;
        Do not put the raw encryption key, database password, OAuth secrets, or an unredacted environment file in a public repository. Keep a sanitized deployment definition in version control and protect the actual secrets in a restricted password manager, secret store, or encrypted backup.
      &lt;/p&gt;

      &lt;h2 id=&quot;choose-the-database-path-before-writing-the-runbook&quot;&gt;Choose the database path before writing the runbook&lt;/h2&gt;
      &lt;p&gt;
        Self-hosted n8n uses SQLite by default. The database file is &lt;code&gt;~/.n8n/database.sqlite&lt;/code&gt;. PostgreSQL is the other supported database option. The backup and restore commands must match the database your instance actually uses.
      &lt;/p&gt;

      &lt;h3&gt;SQLite: capture a consistent persistent volume&lt;/h3&gt;
      &lt;p&gt;
        The simplest small-instance method is a short maintenance window: stop the n8n application, archive its persistent volume, then start it again. Stopping writes avoids treating an arbitrary live file copy as a consistent database backup. For the standard Docker volume shown in n8n's installation guide, a generic sequence looks like this:
      &lt;/p&gt;
      &lt;pre class=&quot;article-code&quot;&gt;docker compose stop n8n
docker run --rm \
  -v n8n_data:/data:ro \
  -v &quot;$PWD/backups:/backup&quot; \
  alpine tar czf /backup/n8n-data-2026-07-18.tgz -C /data .
docker compose start n8n&lt;/pre&gt;
      &lt;p&gt;
        Replace the service and volume names with the names in your deployment. If downtime is not acceptable, use a storage snapshot or SQLite-aware backup process that guarantees a consistent result. Do not assume that copying &lt;code&gt;database.sqlite&lt;/code&gt; while executions are writing to it is safe.
      &lt;/p&gt;

      &lt;h3&gt;PostgreSQL: use a database dump&lt;/h3&gt;
      &lt;p&gt;
        PostgreSQL's official documentation recommends &lt;code&gt;pg_dump&lt;/code&gt; for logical backups. A custom-format dump works with &lt;code&gt;pg_restore&lt;/code&gt; and is practical for restoring into a fresh database. Adapt the connection values and run the tool from a host or database container that can reach PostgreSQL:
      &lt;/p&gt;
      &lt;pre class=&quot;article-code&quot;&gt;pg_dump --format=custom --file=n8n-2026-07-18.dump n8n&lt;/pre&gt;
      &lt;p&gt;
        The dump does not replace the n8n persistent volume or explicit encryption key. It also does not capture the Compose file, environment settings, proxy configuration, or filesystem binary data. Store those as separate parts of the same dated backup set.
      &lt;/p&gt;

      &lt;h2 id=&quot;add-native-n8n-exports-as-a-second-recovery-layer&quot;&gt;Add native n8n exports as a second recovery layer&lt;/h2&gt;
      &lt;p&gt;
        n8n's Server CLI can export all database entity types. Its documentation positions this tooling for backups and migrations, including moves between SQLite and PostgreSQL. Execution-history data tables are excluded by default because they can be large, and can be included explicitly when your retention requirement needs them.
      &lt;/p&gt;
      &lt;pre class=&quot;article-code&quot;&gt;docker exec -u node n8n \
  n8n export:entities \
  --outputDir=/home/node/.n8n/cli-backup&lt;/pre&gt;
      &lt;p&gt;
        Workflow and credential exports are also useful for selective recovery or versioned copies:
      &lt;/p&gt;
      &lt;pre class=&quot;article-code&quot;&gt;n8n export:workflow --backup --output=backups/workflows/
n8n export:credentials --backup --output=backups/credentials/&lt;/pre&gt;
      &lt;div class=&quot;article-callout&quot;&gt;
        &lt;p&gt;&lt;strong&gt;Avoid decrypted credential exports for routine backups.&lt;/strong&gt; n8n supports a &lt;code&gt;--decrypted&lt;/code&gt; flag for migrations to a different secret key, but the resulting files expose every sensitive value in plain text. If that exceptional path is necessary, isolate, encrypt, restrict, and delete the files after the migration.&lt;/p&gt;
      &lt;/div&gt;

      &lt;h2 id=&quot;a-safe-restore-runbook&quot;&gt;A safe restore runbook&lt;/h2&gt;
      &lt;p&gt;
        First restore into an isolated instance with no production webhooks, schedules, email sends, payment calls, or CRM writes. The first recovery test should never overwrite the only production copy.
      &lt;/p&gt;
      &lt;ol&gt;
        &lt;li&gt;&lt;strong&gt;Record the target.&lt;/strong&gt; Use the same n8n version first, the same database type, and compatible custom-node versions. Upgrade only after the restored instance works.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Create fresh infrastructure.&lt;/strong&gt; Prepare a new Docker volume or empty PostgreSQL database rather than clearing production.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Restore the original encryption key.&lt;/strong&gt; Put the protected &lt;code&gt;N8N_ENCRYPTION_KEY&lt;/code&gt; or original n8n settings in place before n8n reads the restored credentials.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Restore the database.&lt;/strong&gt; Extract the stopped SQLite volume archive into the new volume, or restore the PostgreSQL dump into the new database.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Restore the surrounding state.&lt;/strong&gt; Reapply deployment settings, binary storage, custom nodes, public URL settings, and reverse-proxy configuration.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Start without production traffic.&lt;/strong&gt; Keep DNS, proxy routing, and outbound side effects isolated while checking startup and migration logs.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Verify the application.&lt;/strong&gt; Confirm login, projects, workflows, credentials, node availability, execution history required by policy, and binary files that should still exist.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Run one safe test.&lt;/strong&gt; Use test credentials or a non-destructive workflow and confirm that a credential can decrypt and authenticate.&lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Publish deliberately.&lt;/strong&gt; Review which workflows should be published before switching traffic. Imported workflows can have different active-state behavior depending on the import path and deployment mode.&lt;/li&gt;
      &lt;/ol&gt;

      &lt;h3&gt;Restore a SQLite archive into a new volume&lt;/h3&gt;
      &lt;p&gt;
        A new volume keeps the original recoverable while you inspect the restore. This example extracts the archive created above without deleting the production volume:
      &lt;/p&gt;
      &lt;pre class=&quot;article-code&quot;&gt;docker volume create n8n_restore_data
docker run --rm \
  -v n8n_restore_data:/data \
  -v &quot;$PWD/backups:/backup:ro&quot; \
  alpine tar xzf /backup/n8n-data-2026-07-18.tgz -C /data&lt;/pre&gt;
      &lt;p&gt;
        Point a separate restore Compose file at &lt;code&gt;n8n_restore_data&lt;/code&gt;. Do not bind it to the production hostname or webhook route until the checklist passes.
      &lt;/p&gt;

      &lt;h3&gt;Restore PostgreSQL into a fresh database&lt;/h3&gt;
      &lt;pre class=&quot;article-code&quot;&gt;createdb n8n_restore
pg_restore --dbname=n8n_restore n8n-2026-07-18.dump&lt;/pre&gt;
      &lt;p&gt;
        Real deployments may need explicit host, user, role, ownership, TLS, and schema options. Test the exact command your operator will use and document it beside the backup job without embedding the password.
      &lt;/p&gt;

      &lt;h2 id=&quot;restore-test-checklist&quot;&gt;Restore-test checklist&lt;/h2&gt;
      &lt;ul&gt;
        &lt;li&gt;The backup job has a timestamp, size, success state, and failure alert.&lt;/li&gt;
        &lt;li&gt;The database and encryption key come from the same recoverable setup.&lt;/li&gt;
        &lt;li&gt;The restore starts on a separate hostname, volume, and database.&lt;/li&gt;
        &lt;li&gt;Credential nodes open without decryption errors and one test authentication succeeds.&lt;/li&gt;
        &lt;li&gt;Required custom or community nodes load at the expected versions.&lt;/li&gt;
        &lt;li&gt;Published workflows, schedules, and webhook paths are reviewed before traffic moves.&lt;/li&gt;
        &lt;li&gt;Required retained binary files can be opened.&lt;/li&gt;
        &lt;li&gt;The restore time and missing manual steps are recorded for the next test.&lt;/li&gt;
      &lt;/ul&gt;

      &lt;h2 id=&quot;common-backup-failures&quot;&gt;Common backup failures&lt;/h2&gt;
      &lt;div class=&quot;article-table-wrap&quot;&gt;
        &lt;table class=&quot;article-table&quot;&gt;
          &lt;thead&gt;
            &lt;tr&gt;
              &lt;th&gt;Mistake&lt;/th&gt;
              &lt;th&gt;What breaks during recovery&lt;/th&gt;
            &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;
            &lt;tr&gt;
              &lt;td&gt;Only exporting workflow JSON&lt;/td&gt;
              &lt;td&gt;Users, projects, settings, retained executions, and complete credential state are not restored as one instance&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;Database without the original key&lt;/td&gt;
              &lt;td&gt;Credentials remain encrypted but cannot be used&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;Copying a live SQLite file casually&lt;/td&gt;
              &lt;td&gt;The backup may not represent one consistent database state&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;Skipping binary storage&lt;/td&gt;
              &lt;td&gt;Execution records may exist while retained documents or images are missing&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;Restoring straight over production&lt;/td&gt;
              &lt;td&gt;A bad archive or wrong configuration can remove the working recovery path&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;
              &lt;td&gt;Never testing the restore&lt;/td&gt;
              &lt;td&gt;Missing keys, permissions, node packages, and undocumented steps appear during the incident&lt;/td&gt;
            &lt;/tr&gt;
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/div&gt;

      &lt;h2 id=&quot;common-questions&quot;&gt;Common questions&lt;/h2&gt;
      &lt;h3&gt;Where does Docker store self-hosted n8n data?&lt;/h3&gt;
      &lt;p&gt;
        n8n's standard Docker example mounts a named &lt;code&gt;n8n_data&lt;/code&gt; volume at &lt;code&gt;/home/node/.n8n&lt;/code&gt;. Your Compose file may use a different volume or bind mount, so inspect the deployment rather than assuming the example name.
      &lt;/p&gt;

      &lt;h3&gt;Does exporting workflows back up credentials?&lt;/h3&gt;
      &lt;p&gt;
        Not by itself. n8n provides separate workflow and credential export commands, plus the broader &lt;code&gt;export:entities&lt;/code&gt; command. For same-instance disaster recovery, the database, original encryption key, config, and storage remain the stronger complete backup set.
      &lt;/p&gt;

      &lt;h3&gt;Can I restore into a newer n8n version?&lt;/h3&gt;
      &lt;p&gt;
        Restore the recorded version first when possible. This separates backup problems from application migrations. After the restored instance passes its checks, read the intervening release notes, take another backup, and perform the upgrade as a separate controlled change.
      &lt;/p&gt;

      &lt;h2 id=&quot;sources-checked&quot;&gt;Sources checked&lt;/h2&gt;
      &lt;ul&gt;
        &lt;li&gt;&lt;a href=&quot;https://docs.n8n.io/hosting/installation/docker/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;n8n Docker persistence and PostgreSQL guidance&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://docs.n8n.io/hosting/configuration/supported-databases-settings/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;n8n supported databases and SQLite location&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://docs.n8n.io/hosting/configuration/configuration-examples/encryption-key/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;n8n encryption-key behavior&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://docs.n8n.io/hosting/cli-commands/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;n8n Server CLI export and import commands&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://docs.n8n.io/hosting/scaling/binary-data/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;n8n binary-data storage modes&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://www.postgresql.org/docs/current/backup-dump.html&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;PostgreSQL SQL dump documentation&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;https://sqlite.org/backup.html&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;SQLite online backup documentation&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;

      &lt;div class=&quot;article-referral-card&quot;&gt;
        &lt;div&gt;
          &lt;p class=&quot;article-referral-kicker mono&quot;&gt;n8n partner link&lt;/p&gt;
          &lt;p class=&quot;cta-h&quot;&gt;Prefer a managed recovery path?&lt;/p&gt;
          &lt;p&gt;I may earn a commission if you sign up through this link, at no extra cost to you.&lt;/p&gt;
        &lt;/div&gt;
        &lt;a href=&quot;https://n8n.partnerlinks.io/6mg2xng7s1m6&quot; target=&quot;_blank&quot; rel=&quot;sponsored noopener nofollow&quot; class=&quot;btn btn-primary article-referral-button&quot;&gt;Try n8n Cloud&lt;/a&gt;
      &lt;/div&gt;

      &lt;nav class=&quot;article-related&quot; aria-label=&quot;Related reading&quot;&gt;
        &lt;p class=&quot;article-related-h mono&quot;&gt;Keep reading&lt;/p&gt;
        &lt;ul&gt;
          &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/cases/self-hosted-n8n-deployment-docker-cloudflare&quot;&gt;Self-Hosted n8n with Docker, PostgreSQL, and Cloudflare&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/blog/n8n-cloud-vs-self-hosted-cost&quot;&gt;n8n Cloud vs Self-Hosted: The Real Cost&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/blog/n8n-error-workflow-telegram-alerts&quot;&gt;Protect n8n Workflows with Error Alerts&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/cases/website-uptime-monitoring-n8n&quot;&gt;Website Uptime Monitoring with n8n&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/nav&gt;

      &lt;div class=&quot;article-cta&quot;&gt;
        &lt;p class=&quot;cta-h&quot;&gt;Need the recovery path documented?&lt;/p&gt;
        &lt;p&gt;Send the database type, deployment shape, storage locations, and recovery target. I will help map a backup set and an isolated restore test without exposing production secrets.&lt;/p&gt;
        &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/#contact&quot; class=&quot;btn btn-primary article-cta-button&quot;&gt;Map the restore&lt;/a&gt;
      &lt;/div&gt;
&lt;p&gt;&lt;em&gt;Originally published on &lt;a rel=&quot;nofollow&quot; href=&quot;https://floxolab.com/blog/backup-restore-self-hosted-n8n&quot;&gt;FloxoLab&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/25673/how-to-back-up-and-restore-self-hosted-n8n</guid>
<pubDate>Mon, 12 Oct 2026 15:50:00 +0000</pubDate>
</item>
<item>
<title>Why I run my home lab like enterprise infrastructure</title>
<link>https://coderlegion.com/25155/why-i-run-my-home-lab-like-enterprise-infrastructure</link>
<description>&lt;p&gt;&lt;em&gt;Originally published on DEV Community in July 2026. This version is updated with the current state of the lab and a new section on what happened when I finally tested my backups.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I'm an IT Systems Administrator / Service Desk Team Lead L2 in Torino, Italy. During the day I manage endpoints and infrastructure for a large public-sector IT provider. At night I run &lt;strong&gt;PolarisCore&lt;/strong&gt;, a home lab built with the same standards I use at work: VLAN segmentation, a real reverse proxy, internal DNS, ZFS storage with redundancy, and monitoring. Not a pile of Docker containers on a single box.&lt;/p&gt;
&lt;p&gt;Here's the current state, pulled live via SSH an hour before publishing.&lt;/p&gt;
&lt;h3 id=&quot;the-compute-layer-proxmox&quot;&gt;The compute layer — Proxmox&lt;/h3&gt;
&lt;p&gt;When I wrote the original version of this article, the lab ran on a single Proxmox node with 7.5 GiB of RAM. I had assigned about 10 GiB across the containers. Linux lets you over-commit memory, so it worked until it didn't, and the OOM killer took a container roughly once a month.&lt;/p&gt;
&lt;p&gt;A mainboard swap fixed that this week:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;pve-manager/9.2.11 (kernel 7.0.14-12-pve)
Host: HP EliteDesk 800 G5, i7-8700T (12 threads)
Uptime: 4 hours (fresh install)
RAM: 12 / 31 GiB used
ZFS rpool (NVMe mirror): 74.3 GB / 236 GB (31%)
Guests: 14 LXC running / 17 total, plus 1 VM
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those containers handle a Caddy reverse proxy, internal DNS (PowerDNS + Pi-hole), a self-built deployment tool, a Next.js search frontend, a job scheduler, an asset inventory, and a handful of smaller services. VLANs separate management, services, IoT, gaming, guest and VPN traffic, with the services VLAN carrying most of what faces the internet.&lt;/p&gt;
&lt;p&gt;One detail worth stealing: the node has a single physical NIC. Every VLAN reaches it through one VLAN-aware Linux bridge with 802.1Q tagging, and the switch port is a trunk.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;iface nic0 inet manual

auto vmbr0
    bridge-ports nic0
    bridge-vlan-aware yes
    bridge-vids 2-4094
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I spent a day convinced I needed a second network card before I checked how the old node was actually wired and found it had been doing exactly this all along. Read your own configs before you buy hardware.&lt;/p&gt;
&lt;h3 id=&quot;the-storage-layer-truenas-scale&quot;&gt;The storage layer — TrueNAS SCALE&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;TrueNAS 25.10.6
Uptime: 9 hours
Pool DATA (RAIDZ1, 4x8TB): 14.1 TB / 21.8 TB used (64%)
Pool APPS (mirror): 93.8 GB / 460 GB used (20%)
Pool boot: 10.2 GB / 236 GB used (4%)
All pools: ONLINE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;22 TB isn't there for the sake of it. It holds a media library (Jellyfin and the *arr stack, running as native TrueNAS apps rather than VMs), project data, and a dedicated encrypted share. RAIDZ1 across four drives gives me a single-drive failure buffer, which for a setup holding real data matters more to me than raw speed.&lt;/p&gt;
&lt;h3 id=&quot;the-part-i-got-wrong-backups&quot;&gt;The part I got wrong: backups&lt;/h3&gt;
&lt;p&gt;This is the section that wasn't in the original article, and it's the one worth reading.&lt;/p&gt;
&lt;p&gt;While preparing the container migration to the new node, I opened the backup storage to confirm I had a rollback path. The most recent archive was dated 19 April. It covered 4 containers out of 14.&lt;/p&gt;
&lt;p&gt;For four months I believed I had a safety net. It covered less than a third of the machines and was four months stale. Nothing had alerted me. No email, no red icon in the interface, no failing job. The backup job was configured against an explicit list of container IDs, that list had been written once, and the lab had grown past it. A job that backs up four containers successfully reports success.&lt;/p&gt;
&lt;p&gt;So I ran a full backup of everything. It failed on all seventeen guests with the same error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;tar: failed to return to initial working directory: Permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The cause is a two-layer UID translation. Unprivileged LXC containers map their internal users to a host range starting at 100000. The NFS server the backups were written to applies its own remapping on top. The result is a &lt;code&gt;tar&lt;/code&gt; process whose working directory becomes unreachable to it partway through, so it can't &lt;code&gt;chdir&lt;/code&gt; back when it finishes.&lt;/p&gt;
&lt;p&gt;The fix is one flag:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;vzdump --all 1 --storage &amp;lt;target&amp;gt; --mode snapshot --tmpdir /var/tmp/vzdump
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--tmpdir&lt;/code&gt; keeps the working directory on local disk instead of the network share. The archive still lands on the share; only the scratch path moves.&lt;/p&gt;
&lt;p&gt;Seventeen archives, then seventeen restores onto the new node. Sixteen of sixteen running containers came back on the first attempt, and the seventeenth was already powered off by design. That was the first time those archives had ever been read by anyone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The lesson isn't &quot;make backups.&quot; Everyone makes backups.&lt;/strong&gt; The lesson is that a backup job reports on what you told it to do, not on what you needed it to do, and the only way to learn the difference is to restore.&lt;/p&gt;
&lt;h3 id=&quot;the-backup-layer-proxmox-backup-server&quot;&gt;The backup layer — Proxmox Backup Server&lt;/h3&gt;
&lt;p&gt;The old node didn't get retired. It became the backup target:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Proxmox Backup Server 4.2.5
Host: HP EliteDesk 800 G4, i5-8500T (6 cores), 7.53 GiB RAM
Datastore backup-ct: 40.20 GB / 245.55 GB used (16.37%)
Backup count: 17 CT groups, 1 VM group — 18 snapshots
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first full run finished in ten minutes for eighteen guests. It now runs nightly at 02:30 against every guest, with deduplication, a weekly integrity verification job, and a retention policy that keeps 7 daily, 4 weekly and 6 monthly snapshots.&lt;/p&gt;
&lt;p&gt;Three properties make this better than what I had before:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;It backs up &lt;code&gt;--all&lt;/code&gt;, not a list.&lt;/strong&gt; A new container is protected the night it's created, with no config change. That single flag is the direct fix for the failure above.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deduplication is content-addressed at the chunk level.&lt;/strong&gt; Seventeen Debian containers share most of their filesystem, so they cost far less than seventeen times one container.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verification is a separate scheduled job.&lt;/strong&gt; Restoring is still the only real test, but a weekly checksum pass catches silent corruption without me remembering to look.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;One thing I have not solved: the backup server sits in the same cabinet as the machine it backs up. That protects me against disk failure and my own mistakes. It does nothing against fire or theft. An off-site copy of the critical subset is the next job on the list, and I'd rather say that out loud than let the diagram imply I'm covered.&lt;/p&gt;
&lt;h4 id=&quot;the-alerting-trap-again&quot;&gt;The alerting trap, again&lt;/h4&gt;
&lt;p&gt;I configured email notifications and sent a test. It bounced:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;550-5.7.1 Messages missing a valid Message-ID header are not accepted
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gmail doesn't accept mail sent directly from a residential IP address. The fix was routing through an authenticated SMTP relay on port 587 with an app password instead of delivering directly.&lt;/p&gt;
&lt;p&gt;Notice the shape of this. If I hadn't sent that test, the only channel that tells me a backup failed would have been silently discarding every message. I would have rebuilt exactly the situation I had just spent a day fixing: a system that looks healthy because nothing is reporting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test the alerting path, not only the thing being alerted on.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-network-layer&quot;&gt;The network layer&lt;/h3&gt;
&lt;p&gt;FTTH 10 Gbps from TIM into a UniFi Cloud Gateway Max, distributed over a 2.5 GbE backbone to switches and clients. The 10 Gbps WAN isn't about single-stream throughput to the internet. It's headroom, so the internal backbone never bottlenecks against the uplink when backups, streaming and syncs run in parallel. TLS is a wildcard certificate issued via DNS-01, auto-renewing, with zero inbound ports opened for issuance.&lt;/p&gt;
&lt;p&gt;A debugging note from this week that cost me an hour. The new node negotiated its link at 100 Mb/s while everything else ran at 1000 or 2500. My first theory was a bad cable, and I was wrong: the cable was a perfectly good Cat 7. &lt;code&gt;ethtool&lt;/code&gt; showed the real answer, that the machine advertised 1000baseT/Full while the link partner advertised only up to 100baseT/Full. Autonegotiation had settled on 100 during one of the many power cycles that day and never retried, because it doesn't. Forcing the speed once and then re-enabling autoneg fixed it, and a small boot service now re-negotiates if it ever finds itself at 100 again.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ethtool &amp;lt;iface&amp;gt; | grep -A2 &quot;Link partner advertised link modes&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That one command separates &quot;the cable is broken&quot; from &quot;the link is stuck&quot;, and they have completely different fixes.&lt;/p&gt;
&lt;h3 id=&quot;the-lightweight-cloud-piece-oracle-always-free&quot;&gt;The lightweight cloud piece — Oracle Always Free&lt;/h3&gt;
&lt;p&gt;Not everything lives on-prem. Site analytics run on Umami, self-hosted, replacing GA4 across five sites, on an Oracle Cloud Always Free VM:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;Ubuntu 20.04.6 LTS
VM.Standard.A1.Flex — 1 OCPU / 6 GB RAM
RAM used: 694 MiB (11%)
Uptime: 6 weeks
Stack: Umami + Postgres 15 + Caddy, Docker Compose
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Six weeks of uptime and it barely registers on CPU. For a low-traffic analytics backend the free tier is more than enough, and there's no reason to pay for a VPS to do this.&lt;/p&gt;
&lt;h3 id=&quot;a-side-project-that-came-out-of-daily-frustration&quot;&gt;A side project that came out of daily frustration&lt;/h3&gt;
&lt;p&gt;The one piece of software here that isn't infrastructure glue is &lt;strong&gt;NovaSCM&lt;/strong&gt;, an open-source self-hosted alternative to Microsoft SCCM for zero-touch Windows deployment: PXE boot, autounattend generation, network scanning, WiFi 802.1X certificate management, and workflow-based software deployment. It's MIT-licensed, lives on &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/ClaudioBecchis/NovaSCM&quot;&gt;GitHub&lt;/a&gt;, and runs as one of the containers above.&lt;/p&gt;
&lt;h3 id=&quot;why-bother-with-all-this-at-home&quot;&gt;Why bother with all this at home&lt;/h3&gt;
&lt;p&gt;Building it the enterprise way, with segmentation, real certificate automation, redundant storage and a reverse proxy instead of exposed ports, is the best way I know to understand those patterns rather than read about them.&lt;/p&gt;
&lt;p&gt;The backup story above is the argument in miniature. I have written backup procedures at work. I have reviewed them. I still had a four-month gap in my own lab, because reviewing a procedure and restoring from it are different activities, and only one of them tells you the truth. When something breaks at 11 pm on my own network, nobody is going to open a ticket about it, and there's no second line to escalate to. That's a different kind of pressure, and it teaches differently.&lt;/p&gt;
&lt;p&gt;More on the project and the services I haven't written up yet at &lt;a rel=&quot;nofollow&quot; href=&quot;https://polariscore.it&quot;&gt;polariscore.it&lt;/a&gt;.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25155/why-i-run-my-home-lab-like-enterprise-infrastructure</guid>
<pubDate>Sat, 22 Aug 2026 20:19:51 +0000</pubDate>
</item>
<item>
<title>Simple backups using Rsync with SSH</title>
<link>https://coderlegion.com/11514/simple-backups-using-rsync-with-ssh</link>
<description>&lt;p&gt;This post explains how to SSH with Rsync to make backup of your system efficiently and securely.&lt;/p&gt;
&lt;p&gt;The only requisite to start here is an access to SSH somewhere.&lt;/p&gt;
&lt;h3 id=&quot;create-your-ssh-keys&quot;&gt;Create your ssh keys&lt;/h3&gt;
&lt;p&gt;Here, i just create a keypair called “rsync”, ssh will create a private and a public key.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh-keygen -t ed25519 -o -a 100 -f ~/.ssh/rsync
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After, just send the public key to the server with scp targeting your server.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; scp ~/.ssh/rsync.pub backup@SERVER
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;create-a-backup-script&quot;&gt;Create a backup script&lt;/h3&gt;
&lt;p&gt;Create a shell script named rsync-backup.sh with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#/usr/bin/env sh

set -o errexit

# All variables
SERVER=&quot;192.168.1.11&quot;
BACKUP_FILE=&quot;/tmp/backup.filter&quot;

# More efficient than playing with --include,--exclude
cat &amp;lt;&amp;lt; EOF &amp;gt; &quot;$BACKUP_FILE&quot;
# Include patterns
+ /documents/***
+ /Downloads/***
+ /downloads/***
+ /images/***
+ /musics/***

# Exclude everything else
- /**
EOF

# And finally the rsync command
rsync -avP --delete -e &quot;ssh -i $HOME/.ssh/rsync&quot; \
    --bwlimit=400 \
    --filter=&quot;merge $BACKUP_FILE&quot; \
    &quot;$HOME/&quot; &quot;backup@${SERVER}:backups/&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The script here will backup your $HOME with only certain directory in the “include pattern list”. Just ensure the server address is correct.&lt;/p&gt;
&lt;p&gt;I also limit the bandwidth because it break my wifi card (bad hardware…)&lt;/p&gt;
&lt;h3 id=&quot;execute-the-script&quot;&gt;Execute the script&lt;/h3&gt;
&lt;p&gt;Just give permission and launch the script.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; chmod u+x rsync-backup.sh
./rsync-backup.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Using SSH with Rsync is an efficient and secure method for backing up your system. By generating SSH keys and creating a simple shell script, you can automate the backup process, ensuring that your important files are safely stored on a remote server.&lt;/p&gt;
&lt;p&gt;Adjusting settings like bandwidth limitation can help optimize performance, especially on networks with limited resources. This approach not only provides a reliable backup solution but also enhances data security through encrypted connections.&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/11514/simple-backups-using-rsync-with-ssh</guid>
<pubDate>Thu, 12 Feb 2026 13:35:25 +0000</pubDate>
</item>
<item>
<title>Your WordPress Site Will Fail. Be Ready.</title>
<link>https://coderlegion.com/8595/your-wordpress-site-will-fail-be-ready</link>
<description>&lt;blockquote&gt;&lt;p&gt;After losing two weeks of work to a crash, I spent years perfecting my&lt;br&gt;
backup strategy. Here's everything I learned managing 10+ client&lt;br&gt;
sites.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;why-i-m-writing-this&quot;&gt;Why I'm Writing This&lt;/h3&gt;
&lt;p&gt;Three years ago, I lost two weeks of work because I trusted backups I never tested. The panic, the scrambling, the realization that my &quot;backup solution&quot; was just an empty promise — I wouldn't wish that on anyone.&lt;/p&gt;
&lt;p&gt;Since then, I've done 20+ website restorations, tested every major backup plugin, and built a system that works so well I actually sleep at night. I &lt;a rel=&quot;nofollow&quot; href=&quot;https://kolodych.com/articles/wordpress-backup-guide.html?coderlegion.com&quot;&gt;documented the complete process on my site&lt;/a&gt;, but wanted to share it here with the CoderLegion.com community too.&lt;/p&gt;
&lt;p&gt;Because if there's one thing I've learned: &lt;strong&gt;hope is not a backup strategy.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;website-crashes-are-normal&quot;&gt;Website Crashes Are Normal&lt;/h3&gt;
&lt;p&gt;Updates fail. Plugins conflict. Servers go down. Themes break layouts. Hackers exploit weak spots.&lt;/p&gt;
&lt;p&gt;You do not control when this happens. You control how fast you recover.&lt;/p&gt;
&lt;p&gt;Most site owners panic. They search logs. They contact hosting. They wait. Hours pass. Sometimes days. Without backups, recovery becomes guesswork.&lt;/p&gt;
&lt;p&gt;A backup removes fear. It turns a crash into a routine task. Restore. Check. Move on.&lt;/p&gt;
&lt;h3 id=&quot;the-wordpress-backup-plugin-solution&quot;&gt;The WordPress Backup Plugin Solution&lt;/h3&gt;
&lt;p&gt;While there are many backup plugins available, not all are created equal. Some are lightweight and reliable, while others can slow down your site or cause conflicts.&lt;/p&gt;
&lt;p&gt;I've tried them all: UpdraftPlus, Backuply, Jetpack, BackWPup, WPvivid, Duplicator, All-in-One WP Migration.&lt;/p&gt;
&lt;p&gt;After 20+ website restorations, &lt;a rel=&quot;nofollow&quot; href=&quot;https://wordpress.org/plugins/wpvivid-backuprestore/&quot;&gt;WPvivid&lt;/a&gt; is my choice. It strikes the perfect balance between comprehensive protection and ease of use, without the complexity that makes you need a computer science degree to configure it properly.&lt;/p&gt;
&lt;p&gt;What WPvivid Can Do For You&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ Full website backups&lt;/li&gt;
&lt;li&gt;✅ Database-only backups&lt;/li&gt;
&lt;li&gt;✅ Files-only backups&lt;/li&gt;
&lt;li&gt;✅ Manual backups on demand&lt;/li&gt;
&lt;li&gt;✅ Automatic scheduled backups&lt;/li&gt;
&lt;li&gt;✅ One-click restore&lt;/li&gt;
&lt;li&gt;✅ Website migration&lt;/li&gt;
&lt;li&gt;✅ Staging site creation&lt;/li&gt;
&lt;li&gt;✅ Remote storage support (Google Drive, Dropbox, Microsoft OneDrive,&lt;br&gt;
Amazon S3, FTP, SFTP)&lt;/li&gt;
&lt;li&gt;✅ Backup splitting for large sites&lt;/li&gt;
&lt;li&gt;✅ Incremental backups in Pro version&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;your-first-backup-with-wpvivid&quot;&gt;Your First Backup with WPvivid&lt;/h3&gt;
&lt;p&gt;Here's the critical part most tutorials skip: &lt;strong&gt;you need to verify that it works correctly for YOUR specific setup.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every website is unique — different themes, plugins, hosting environments and configurations. Backups mean nothing if restore fails.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Never trust blindly — test once, then relax.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-1-create-your-first-backup&quot;&gt;Step 1: Create Your First Backup&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Install and activate WPvivid plugin&lt;/li&gt;
&lt;li&gt;Open WPvivid Backup in WordPress, tab &quot;Backup &amp;amp; Restore&quot;&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=17141164007944580133&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;li&gt;Choose &quot;Database + Files&quot;&lt;/li&gt;
&lt;li&gt;Choose &quot;Save to Local&quot;&lt;/li&gt;
&lt;li&gt;Click &quot;Backup Now&quot;&lt;/li&gt;
&lt;li&gt;Wait for the backup to complete&lt;/li&gt;
&lt;li&gt;Reload the page, click &quot;Scan uploaded backup or received backup&quot;,&lt;br&gt;
then click &quot;Download&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Congratulations! You have your first backup. But we're not done yet.&lt;/p&gt;
&lt;h3 id=&quot;testing-the-restore-process-the-most-important-part-&quot;&gt;Testing the Restore Process (THE MOST IMPORTANT PART)&lt;/h3&gt;
&lt;p&gt;This is where most people stop. Don't be most people.&lt;/p&gt;
&lt;h3 id=&quot;step-2-test-on-a-blank-wordpress-site&quot;&gt;Step 2: Test on a Blank WordPress Site&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Create a blank test WordPress site (use a subdomain or local&lt;br&gt;
environment)&lt;/li&gt;
&lt;li&gt;Install and activate WPvivid plugin on the test site&lt;/li&gt;
&lt;li&gt;In the test site, open WPvivid, tab &quot;Backup &amp;amp; Restore&quot;&lt;/li&gt;
&lt;li&gt;Scroll down to find the &quot;Upload&quot; section&lt;/li&gt;
&lt;li&gt;Click 'Upload' and select the backup file from your local machine&lt;/li&gt;
&lt;li&gt;Wait for &quot;The upload has completed&quot; message - click &quot;OK&quot;WPvivid&lt;br&gt;
Restore backup process&lt;br&gt;
&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=9469043099860066014&quot; alt=&quot;&quot;&gt;&lt;/li&gt;
&lt;li&gt;Click the &quot;Backups&quot; button (located next to the 'Upload' button)&lt;/li&gt;
&lt;li&gt;You should see the uploaded backup - click &quot;Restore&quot; and then&lt;br&gt;
&quot;Restore&quot; again&lt;/li&gt;
&lt;li&gt;Click &quot;OK&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: Don't close or switch to other tabs during the restore process.&lt;/p&gt;
&lt;p&gt;When finished you'll get the message &quot;Restore completed successfully&quot; - click &quot;OK&quot;.&lt;/p&gt;
&lt;h3 id=&quot;step-3-verify-everything-works&quot;&gt;Step 3: Verify Everything Works&lt;/h3&gt;
&lt;p&gt;Reload the page. Go to different pages and sections of your website. Confirm everything is working as expected.&lt;/p&gt;
&lt;p&gt;This entire test process takes 5-60 minutes (depending on the size of your site) and is worth every second.&lt;/p&gt;
&lt;h3 id=&quot;why-testing-matters-my-hard-learned-lessons-&quot;&gt;Why Testing Matters (My Hard-Learned Lessons)&lt;/h3&gt;
&lt;p&gt;I test my backups every couple of months. Here are issues I've caught BEFORE they became disasters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;❌ File corrupted during transfer&lt;/li&gt;
&lt;li&gt;❌ PHP timeout during restore&lt;/li&gt;
&lt;li&gt;❌ Incompatible plugin files&lt;/li&gt;
&lt;li&gt;❌ Invalid backup file format&lt;/li&gt;
&lt;li&gt;...and so much more that can go wrong&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That's why for every website I have or make, I create a test website to verify the backup works. This practice gives me peace of mind and ensures my clients' websites are always protected and recoverable.&lt;/p&gt;
&lt;h3 id=&quot;setting-up-remote-storage-critical-&quot;&gt;Setting Up Remote Storage (CRITICAL)&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=15630696678842578760&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I hope you now understand the importance of having your backups NOT in the same place as your website.&lt;/p&gt;
&lt;h3 id=&quot;configure-remote-storage-&quot;&gt;Configure Remote Storage:&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=4592608848892023262&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to tab &quot;Remote Storage&quot;&lt;/li&gt;
&lt;li&gt;Click on the cloud service you prefer (Google Drive, Dropbox, etc.)&lt;/li&gt;
&lt;li&gt;Click &quot;Authenticate&quot; (log in to your account)&lt;/li&gt;
&lt;li&gt;Give it a descriptive name so you'll know where to find your backups&lt;br&gt;
later&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;automating-your-backups&quot;&gt;Automating Your Backups&lt;/h3&gt;
&lt;p&gt;Now let's set it and forget it:&lt;/p&gt;
&lt;h3 id=&quot;schedule-settings-&quot;&gt;Schedule Settings:&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=4354510276759218365&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to tab &quot;Schedule&quot;&lt;/li&gt;
&lt;li&gt;Tick &quot;Enable backup schedule&quot;&lt;/li&gt;
&lt;li&gt;Choose frequency (daily or weekly - I recommend daily for active&lt;br&gt;
sites)&lt;/li&gt;
&lt;li&gt;Choose &quot;Database + Files&quot;&lt;/li&gt;
&lt;li&gt;Select &quot;Send backups to remote storage&quot; (your authenticated service&lt;br&gt;
will show as active)&lt;br&gt;
 &lt;strong&gt;6. Most importantly: Click &quot;Save&quot;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;general-settings-&quot;&gt;General Settings:&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://coderlegion.com/?qa=blob&amp;amp;qa_blobid=2160534488618077067&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to tab &quot;Settings&quot; → &quot;General settings&quot;&lt;/li&gt;
&lt;li&gt;Set maximum backups retained = 7 (keeps one week of daily backups)&lt;/li&gt;
&lt;li&gt;Tick &quot;Merge all the backup files into single package&quot;&lt;/li&gt;
&lt;li&gt;Click &quot;Save&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;faq&quot;&gt;FAQ&lt;/h3&gt;
&lt;h3 id=&quot;how-often-should-i-backup-my-wordpress-site-&quot;&gt;How often should I backup my WordPress site?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Most websites:&lt;/strong&gt; Daily backups&lt;br&gt;
 &lt;strong&gt;- E-commerce sites:&lt;/strong&gt; Multiple times per day&lt;br&gt;
 &lt;strong&gt;- Blogs with infrequent updates:&lt;/strong&gt; Weekly backups&lt;br&gt;
 &lt;strong&gt;- The key:&lt;/strong&gt; Always backup before any major changes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;why-should-i-test-my-wordpress-backups-&quot;&gt;Why should I test my WordPress backups?&lt;/h3&gt;
&lt;p&gt;Testing backups ensures they actually work when disaster strikes. Many website owners discover their backups are corrupted or incomplete only after they need them.&lt;/p&gt;
&lt;h3 id=&quot;is-wpvivid-free-&quot;&gt;Is WPvivid free?&lt;/h3&gt;
&lt;p&gt;Yes! WPvivid has a robust free version that includes full site backups, scheduling, cloud storage integration, and one-click restore. The premium version adds incremental backups, staging sites, and advanced features for $79/year.&lt;/p&gt;
&lt;h3 id=&quot;the-results-peace-of-mind&quot;&gt;The Results: Peace of Mind&lt;/h3&gt;
&lt;p&gt;Since implementing this system, I've had:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Servers crash&lt;/li&gt;
&lt;li&gt;Hard drives fail&lt;/li&gt;
&lt;li&gt;Hosting accounts suspended due to billing errors&lt;/li&gt;
&lt;li&gt;Security breaches that required immediate rollback&lt;/li&gt;
&lt;li&gt;Plugin updates that broke entire sites&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Every single time:&lt;/strong&gt; Restored from backup and was back online within 20 minutes.&lt;/p&gt;
&lt;p&gt;My clients never knew there was a problem. My visitors never saw downtime. I never lost sleep or spent hours on emergency support calls.&lt;/p&gt;
&lt;h3 id=&quot;one-final-rule&quot;&gt;One Final Rule&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;If you remember nothing else from this article, remember this:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every update — every single one — should happen on a test environment first. Not sometimes. Not for &quot;small&quot; updates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every. Single. Time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I learned this the hard way. You don't have to.&lt;/p&gt;
&lt;h3 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;/h3&gt;
&lt;p&gt;If you want even more details, screenshots, and specific settings, I've documented everything on my site: &lt;a rel=&quot;nofollow&quot; href=&quot;https://kolodych.com/articles/wordpress-backup-guide.html?coderlegion.com&quot;&gt;Complete WordPress Backup Guide&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can also check out my other web development guides:&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://kolodych.com/articles/nginx.html?coderlegion.com&quot;&gt;Nginx: What is It and Why Should You Care?&lt;/a&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://kolodych.com/website/web-dev-tools.html?coderlegion.com&quot;&gt;My Go-To Web Arsenal&lt;/a&gt;&lt;br&gt;
&lt;a rel=&quot;nofollow&quot; href=&quot;https://nuukmedia.com/2024/08/mastering-google-search-console-a-complete-guide-for-beginners/?kolodych.com_and_coderlegion.com&quot;&gt;Beginner's Guide to Google Search Console&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What's your backup horror story?&lt;/strong&gt; Drop it in the comments. Let's learn from each other's mistakes.&lt;/p&gt;
</description>
<category>Plugins</category>
<guid isPermaLink="true">https://coderlegion.com/8595/your-wordpress-site-will-fail-be-ready</guid>
<pubDate>Thu, 18 Dec 2025 14:44:03 +0000</pubDate>
</item>
</channel>
</rss>