<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Server Ops on UIPad Blog</title><link>https://blog.uipad.com/categories/server-ops/</link><description>Recent content in Server Ops on UIPad Blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sun, 26 Apr 2026 21:30:00 +0800</lastBuildDate><atom:link href="https://blog.uipad.com/categories/server-ops/index.xml" rel="self" type="application/rss+xml"/><item><title>Docker + Postgres Auth Voodoo: A Troubleshooting Log of a Fatal Nano Auto-Wrap Bug</title><link>https://blog.uipad.com/post/2026-04/docker-postgres-auth-nano-wrap-bug/</link><pubDate>Sun, 26 Apr 2026 21:30:00 +0800</pubDate><guid>https://blog.uipad.com/post/2026-04/docker-postgres-auth-nano-wrap-bug/</guid><description>&lt;p&gt;As an indie developer who constantly tinkers with servers, dealing with Docker is a daily routine. I thought deploying a PostgreSQL instance via &lt;code&gt;docker-compose up -d&lt;/code&gt; was a standard operation I could do with my eyes closed. However, I recently fell headfirst into a cascading series of traps.&lt;/p&gt;
&lt;p&gt;The error message is one we are all too familiar with:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;FATAL: password authentication failed for user &amp;quot;app&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But after repeatedly verifying that my environment variables, network configurations, and even inter-container connectivity were all flawless, things started getting weird. After two days of peeling back the layers, I discovered this wasn&amp;rsquo;t just a simple password typo. It was a triple-threat trap composed of &lt;strong&gt;phantom configurations, volume mounting blind spots, and editor quirks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This post logs the entire debugging process, hoping to save the sanity of anyone else doubting their existence in the terminal.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="trap-1-the-two-negatives-make-a-positive-phantom-password"&gt;Trap 1: The &amp;ldquo;Two Negatives Make a Positive&amp;rdquo; Phantom Password
&lt;/h3&gt;&lt;p&gt;The whole thing started like this: I noticed my newly created App container absolutely refused to connect to Postgres, yet another Auth service I had deployed earlier was connecting just fine.&lt;/p&gt;
&lt;p&gt;At first, I wondered if routing through the internal Docker network (e.g., &lt;code&gt;Host=pgsql&lt;/code&gt;) bypassed the password check. But Postgres&amp;rsquo;s &lt;code&gt;pg_hba.conf&lt;/code&gt; mechanism dictates that TCP connections must use &lt;code&gt;scram-sha-256&lt;/code&gt; validation; passwordless entry simply isn&amp;rsquo;t an option here.&lt;/p&gt;
&lt;p&gt;By directly running an &lt;code&gt;echo&lt;/code&gt; on the environment variables inside the container, I caught the first mole: &lt;strong&gt;unquoted &lt;code&gt;.env&lt;/code&gt; comments&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In an earlier iteration of the project, I had an &lt;code&gt;.env&lt;/code&gt; file written like this:
&lt;code&gt;PGSQL_APP_PASSWORD=app@pgsql # Global app password&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And my &lt;code&gt;docker-compose.yaml&lt;/code&gt; looked like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;POSTGRES_APP_PASSWORD&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${PGSQL_APP_PASSWORD:-app@pgsql}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because the &lt;code&gt;.env&lt;/code&gt; value wasn&amp;rsquo;t enclosed in double quotes, Docker Compose brutally swallowed the trailing spaces and the inline comment right into the environment variable.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;During database initialization, it saved &lt;code&gt;app@pgsql # Global app password&lt;/code&gt; as the complete, literal password.&lt;/li&gt;
&lt;li&gt;The old Auth container read that exact same configuration and made requests using that ridiculously long, comment-included password. &lt;strong&gt;Both sides matched perfectly (two negatives made a positive)!&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Meanwhile, when I manually typed the clean password &lt;code&gt;app@pgsql&lt;/code&gt; in the command line, I was ruthlessly rejected.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; For complex strings in &lt;code&gt;.env&lt;/code&gt; files or &lt;code&gt;docker-compose.yml&lt;/code&gt;, especially passwords with special characters, &lt;strong&gt;always make it a habit to use double quotes&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="trap-2-the-ignored-volume-initialization-blind-spot"&gt;Trap 2: The Ignored Volume Initialization Blind Spot
&lt;/h3&gt;&lt;p&gt;Having discovered the issue above, I decided to fix the config, switch to a clean password &lt;code&gt;app#pgsql&lt;/code&gt;, and restart the container. The result? &lt;strong&gt;Still throwing the same error!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I went inside the container, printed the environment variable, and confirmed &lt;code&gt;$POSTGRES_APP_PASSWORD&lt;/code&gt; was now the correct &lt;code&gt;app#pgsql&lt;/code&gt;. Why couldn&amp;rsquo;t it connect?&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s when I noticed this line in my &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;./data:/var/lib/postgresql/data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This triggers a classic &amp;ldquo;hidden rule&amp;rdquo; of the Postgres Docker image: &lt;strong&gt;As long as the mounted target directory (&lt;code&gt;/var/lib/postgresql/data&lt;/code&gt;) is not empty, the container startup will completely skip the initialization process (including the execution of scripts under &lt;code&gt;/docker-entrypoint-initdb.d/&lt;/code&gt;).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Because I had already spun it up once, the &lt;code&gt;./data&lt;/code&gt; directory on my host machine contained legacy data. Even though I changed the config and restarted the container, the password stored inside the database was still that Chinese-comment-infused &amp;ldquo;phantom password&amp;rdquo; from the first initialization.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip:&lt;/strong&gt; When debugging initialization scripts in a development environment, if you change passwords or the initial database structure, &lt;strong&gt;you must wipe the host&amp;rsquo;s &lt;code&gt;./data&lt;/code&gt; directory&lt;/strong&gt; (&lt;code&gt;rm -rf ./data/*&lt;/code&gt;), or drop into the container and forcefully update the password using &lt;code&gt;ALTER USER&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="final-boss-the-backstab-of-nanos-copy-paste"&gt;Final Boss: The &amp;ldquo;Backstab&amp;rdquo; of Nano&amp;rsquo;s Copy-Paste
&lt;/h3&gt;&lt;p&gt;Alright, I deleted the old data and was certain it would re-initialize this time. The &lt;code&gt;docker logs&lt;/code&gt; clearly showed my custom script &lt;code&gt;01-init-user-and-permissions.sh&lt;/code&gt; executing, even printing &lt;code&gt;NOTICE: User created: app&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I eagerly went to test the connection.
&lt;strong&gt;Error: &lt;code&gt;password authentication failed&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;At that moment, I genuinely started to question if my fundamental understanding of Docker had been tampered with. The network was fine, the environment variables were fine, the data had been wiped clean—where was the ghost?&lt;/p&gt;
&lt;p&gt;It wasn&amp;rsquo;t until I opened that &lt;code&gt;01-init-user-and-permissions.sh&lt;/code&gt; script and scanned it line by line that I finally spotted the incredibly stealthy fatal flaw:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CREATE USER &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$POSTGRES_APP_USER&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; WITH PASSWORD &lt;span style="color:#e6db74"&gt;&amp;#39;$POSTGRES_APP_PASSWO
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt;RD&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, you read that right. &lt;strong&gt;The variable name &lt;code&gt;$POSTGRES_APP_PASSWORD&lt;/code&gt; had been chopped in half by a line break!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;How did this happen?
Because I was working directly in an SSH terminal, using the &lt;code&gt;nano&lt;/code&gt; editor, and I &lt;strong&gt;copied and pasted&lt;/strong&gt; the script from another server.
When your terminal window isn&amp;rsquo;t wide enough, and &lt;code&gt;nano&lt;/code&gt; has its default &lt;strong&gt;Word Wrap&lt;/strong&gt; feature enabled, it takes the liberty of inserting an actual &lt;strong&gt;Hard Return&lt;/strong&gt; right in the middle of long strings.&lt;/p&gt;
&lt;p&gt;In Bash logic, it couldn&amp;rsquo;t find the variable &lt;code&gt;$POSTGRES_APP_PASSWO&lt;/code&gt; (because it was truncated by the return key), so it parsed it as an &lt;strong&gt;empty string&lt;/strong&gt;.
Ultimately, the database successfully executed the SQL, but what it actually ran was:
&lt;code&gt;CREATE USER &amp;quot;app&amp;quot; WITH PASSWORD '';&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The password was blank!&lt;/strong&gt; This was the ultimate reason why my perfectly correct password was constantly failing.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="summary--best-practices"&gt;Summary &amp;amp; Best Practices
&lt;/h3&gt;&lt;p&gt;Stacking these three pitfalls together creates maximum dramatic effect. To prevent myself (or you, the reader) from falling into this trap again, here are a few ironclad rules for development:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Terminal Editor Self-Defense:&lt;/strong&gt;
If you need to paste long code or configs into &lt;code&gt;nano&lt;/code&gt; on a Linux terminal, &lt;strong&gt;always remember to add the &lt;code&gt;-w&lt;/code&gt; flag&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nano -w script.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This disables auto word wrapping and is an absolute lifesaver. An even better approach is using VS Code&amp;rsquo;s Remote SSH extension to edit server files directly, bypassing terminal clipboard torture entirely.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Environment Variable &amp;amp; Password Standards:&lt;/strong&gt;
Wrap &lt;code&gt;.env&lt;/code&gt; passwords and variables containing special characters in double quotes. Keep inline comments on their own separate lines.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Global app password&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PGSQL_APP_PASSWORD&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;app@pgsql&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The 3-Step DB Debugging Axis:&lt;/strong&gt;
When encountering Docker DB password voodoo, drop straight into the host with superadmin privileges to investigate and settle it instantly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 1. Check what configuration the container actually swallowed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker exec -it pgsql /bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo $POSTGRES_APP_PASSWORD
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 2. Force a connection test using the exact environment variable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PGPASSWORD&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$POSTGRES_APP_PASSWORD&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt; psql -h 127.0.0.1 -U app -d postgres
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Server operations are just like this. Sometimes, what tortures you for two straight days isn&amp;rsquo;t some low-level kernel bug, but simply an invisible line break. Documenting this down, mostly as a stark reminder to my future self!&lt;/p&gt;</description></item><item><title>Cross-Cloud Database Resilience: PostgreSQL Streaming Replication with Dual-Cert SSL</title><link>https://blog.uipad.com/post/2026-03/postgresql-cross-cloud-streaming-replication-with-ssl-en/</link><pubDate>Sat, 14 Mar 2026 21:00:00 +0800</pubDate><guid>https://blog.uipad.com/post/2026-03/postgresql-cross-cloud-streaming-replication-with-ssl-en/</guid><description>&lt;p&gt;As an indie developer, &amp;ldquo;Single Point of Failure&amp;rdquo; is the stuff of nightmares. While Oracle Cloud offers a generous Free Tier, relying on a single provider for your production data is risky. To ensure data sovereignty and high availability, I recently implemented a cross-cloud PostgreSQL streaming replication setup.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t just a simple cron-job for backups—it&amp;rsquo;s a real-time &amp;ldquo;Shadow Database&amp;rdquo; architecture.&lt;/p&gt;
&lt;h2 id="1-the-need-for-real-time-replication"&gt;1. The Need for Real-Time Replication
&lt;/h2&gt;&lt;p&gt;Relying solely on daily snapshots had two major drawbacks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RPO (Recovery Point Objective)&lt;/strong&gt;: A crash at 11 PM meant losing a whole day of data if the last backup was at 2 AM.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RTO (Recovery Time Objective)&lt;/strong&gt;: Restoring Giga-bytes of data from S3 to a new container during an outage takes far too long.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;My Goal&lt;/strong&gt;: Maintain a read-only replica on a separate VPS, ready for a minute-level failover.&lt;/p&gt;
&lt;h2 id="2-the-solution-mtls--streaming-replication"&gt;2. The Solution: mTLS + Streaming Replication
&lt;/h2&gt;&lt;p&gt;Since data travels over the public internet, &lt;strong&gt;security&lt;/strong&gt; was non-negotiable.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Encryption&lt;/strong&gt;: TLS is mandatory to prevent sniffing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: Instead of passwords, I used &lt;strong&gt;Mutual TLS (mTLS)&lt;/strong&gt;. Only the server holding a client certificate signed by my private CA can connect to the primary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Isolation&lt;/strong&gt;: Custom ports (e.g., &lt;code&gt;8765&lt;/code&gt;) combined with strict IP whitelisting via &lt;code&gt;iptables&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="3-hard-won-lessons-the-pitfalls"&gt;3. Hard-Won Lessons (The Pitfalls)
&lt;/h2&gt;&lt;h3 id="pitfall-1-docker-vs-system-firewall"&gt;Pitfall #1: Docker vs. System Firewall
&lt;/h3&gt;&lt;p&gt;Docker often bypasses standard &lt;code&gt;ufw&lt;/code&gt; rules by manipulating &lt;code&gt;iptables&lt;/code&gt; directly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Explicitly insert rules into the &lt;code&gt;INPUT&lt;/code&gt; chain for the specific standby IP and persist them using &lt;code&gt;iptables-persistent&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="pitfall-2-the-pg_basebackup-path-ghost"&gt;Pitfall #2: The pg_basebackup Path Ghost
&lt;/h3&gt;&lt;p&gt;When running &lt;code&gt;pg_basebackup&lt;/code&gt; in a temporary container, it hardcodes the ephemeral paths (like &lt;code&gt;/temp_certs&lt;/code&gt;) into &lt;code&gt;postgresql.auto.conf&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Manually edit the config post-clone to point to the permanent volume paths (e.g., &lt;code&gt;/var/lib/postgresql/data/certs/&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="pitfall-3-permissions-the-999-rule"&gt;Pitfall #3: Permissions (The 999 Rule)
&lt;/h3&gt;&lt;p&gt;PostgreSQL is notoriously picky about certificate permissions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Error&lt;/strong&gt;: &lt;code&gt;could not open file &amp;quot;server.key&amp;quot;: Permission denied&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fix&lt;/strong&gt;: Run &lt;code&gt;chown -R 999:999&lt;/code&gt; on the host data directory. Even if it looks like &lt;code&gt;root&lt;/code&gt; on the host, the container process must own it as UID &lt;code&gt;999&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-key-configurations"&gt;4. Key Configurations
&lt;/h2&gt;&lt;h3 id="primary-pg_hbaconf"&gt;Primary &lt;code&gt;pg_hba.conf&lt;/code&gt;
&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-conf" data-lang="conf"&gt;# Only allow replication_user via certificate-based auth
hostssl replication replication_user &amp;lt;Standby_IP&amp;gt;/32 cert
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="standby-postgresqlautoconf"&gt;Standby &lt;code&gt;postgresql.auto.conf&lt;/code&gt;
&lt;/h3&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-conf" data-lang="conf"&gt;primary_conninfo = &amp;#39;user=replication_user host=&amp;lt;Primary_IP&amp;gt; port=8765 sslmode=verify-ca sslcert=/path/to/client.crt sslkey=/path/to/client.key sslrootcert=/path/to/ca.crt&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="5-maintenance-why-i-switched-to-bind-mounts"&gt;5. Maintenance: Why I Switched to Bind Mounts
&lt;/h2&gt;&lt;p&gt;I moved away from Docker Named Volumes to &lt;strong&gt;Bind Mounts&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reason&lt;/strong&gt;: When migrating the standby to a new server, a simple &lt;code&gt;tar&lt;/code&gt; of &lt;code&gt;/opt/pgsql/data&lt;/code&gt; is transparent. No more hunting for obscure Docker volume hashes. It makes migration 200% faster.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;High Availability isn&amp;rsquo;t about showing off; it&amp;rsquo;s about sleeping better at night. Currently, this setup maintains near-zero lag under Uptime Kuma monitoring.&lt;/p&gt;</description></item></channel></rss>