{"id":5299,"date":"2026-08-30T14:10:37","date_gmt":"2026-08-30T05:10:37","guid":{"rendered":"https:\/\/donguri3.net\/server-tech\/oci-nginx-local-ols-ssl-pull-sync-2\/"},"modified":"2026-08-30T14:10:39","modified_gmt":"2026-08-30T05:10:39","slug":"oci-nginx-local-ols-ssl-pull-sync","status":"publish","type":"post","link":"https:\/\/donguri3.net\/en\/server-tech\/linux-server-network\/oci-nginx-local-ols-ssl-pull-sync\/","title":{"rendered":"Solving the Home Server SSL Problem: How to Avoid Certificate Conflicts Between OCI Nginx and Local OLS"},"content":{"rendered":"<p>The server architecture of our blog, &#8220;Nando Kobo,&#8221; has evolved into its current form after overcoming several technical hurdles.<\/p>\n<p>It started as a simple setup: WireGuard(OCI) -&gt; OLS(local) -&gt; WordPress. However, we hit our first roadblock right away. WireGuard&#8217;s iptables forwarding did not properly append the X-Forwarded-For header, which prevented QUIC.cloud integration\u2014essential for WordPress speed optimization\u2014from working correctly.<\/p>\n<p><a href=\"https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1.jpg\"><img decoding=\"async\" class=\"aligncenter size-large wp-image-379\" src=\"https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-1024x576.jpg\" alt=\"Exposing a Web Server within an Apartment Network Using WireGuard and VPS (OCI)\" width=\"1024\" height=\"576\" srcset=\"https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-1024x576.jpg 1024w, https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-300x169.jpg 300w, https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-768x432.jpg 768w, https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-1536x864.jpg 1536w, https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-320x180.jpg 320w, https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-530x298.jpg 530w, https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-565x318.jpg 565w, https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-710x399.jpg 710w, https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-725x408.jpg 725w, https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1-160x90.jpg 160w, https:\/\/donguri3.net\/wp-content\/uploads\/2025\/02\/\u30de\u30f3\u30b7\u30e7\u30f3\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u5185\u306e\u30a6\u30a7\u30d6\u30b5\u30fc\u30d0\u3092\u516c\u958b-1.jpg 1920w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>To solve this issue, we introduced Nginx as a reverse proxy on the OCI side, evolving the architecture to Nginx(OCI) &#8212; WireGuard -&gt; OLS(local).<\/p>\n<p><a href=\"https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b.png\"><img decoding=\"async\" class=\"aligncenter size-large wp-image-2502\" src=\"https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b-1024x576.png\" alt=\"Exposing a Web Server within an Apartment Network Using WireGuard and VPS (OCI) (WordPress + QUIC.cloud Compatible Version)\" width=\"1024\" height=\"576\" srcset=\"https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b-1024x576.png 1024w, https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b-300x169.png 300w, https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b-768x432.png 768w, https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b-1536x864.png 1536w, https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b-320x180.png 320w, https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b-530x298.png 530w, https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b-565x318.png 565w, https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b-710x399.png 710w, https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b-725x408.png 725w, https:\/\/donguri3.net\/wp-content\/uploads\/2026\/01\/4dbae79b62f00eb3fa9b8f777539b57b.png 1920w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>However, the next challenge was &#8220;SSL termination.&#8221; Initially, we tried to handle SSL termination on the OLS side, but we couldn&#8217;t route traffic smoothly through Nginx. Ultimately, we decided to handle SSL termination on Nginx. While this solved the communication issue, it created a new side effect: &#8220;OLS could no longer automatically renew its certificates using acme tools.&#8221;<\/p>\n<h2>The Backend Server Stripped of SSL Renewal &#8220;Authority&#8221;<\/h2>\n<p>Currently, the SSL certificate for public exposure is managed by Nginx on OCI. However, to maintain consistency for local access within the home network and inter-server communication, the exact same valid certificate must also be deployed on the backend OLS.<\/p>\n<p>Since Nginx occupies port 80, OLS cannot reach out to renew its own certificates. On the other hand, manually copy-pasting certificates every three months goes against the aesthetics of Nando Kobo.<\/p>\n<h2>Automating &#8220;Doing Nothing&#8221;: Reducing Manual Annual Updates to &#8220;0&#8221;<\/h2>\n<p>Our target goal is clear.<\/p>\n<ul>\n<li>Reduce manual time spent on SSL renewals to &#8220;0 minutes per year.&#8221;<\/li>\n<li>Bypass network constraints (no pushing from OCI to the home network) and synchronize certificates securely.<\/li>\n<\/ul>\n<p>Rather than giving up with the excuse that &#8220;the architecture is too complex, so manual work is inevitable,&#8221; we will complete the automation while keeping the complex architecture intact.<\/p>\n<h2>The Barrier of Permissions and &#8220;One-Way&#8221; Network Traffic<\/h2>\n<p>When automating this, we faced two major challenges.<\/p>\n<ol>\n<li>Permission Denied: Let&#8217;s Encrypt certificates (\/etc\/letsencrypt\/) are protected by root privileges. Regular SSH users cannot read them, and any attempts to use rsync will be rejected.<\/li>\n<li>Constraint of a Pull-Only Architecture: Even though they are connected via WireGuard, containerized operations and security considerations make it difficult to &#8220;push&#8221; updates from OCI to the home network. A mechanism where the home side &#8220;pulls&#8221; the certificates was essential.<\/li>\n<\/ol>\n<h2>Deploy Hook \u2715 Pull-Type Synchronization \u2715 Graceful Restart<\/h2>\n<p>We solved this challenge in three steps.<\/p>\n<p>1. Preparing the &#8220;Share&#8221; on the OCI Side<br \/>\nWe configure a &#8220;deploy hook&#8221; that leaves the main certificate (owned by root) untouched and creates a copy in a location readable by a regular user only when an update occurs.<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\"># Example Certbot renewal hook configuration on OCI\ncp -L \/etc\/letsencrypt\/live\/your-domain\/fullchain.pem \/home\/ubuntu\/certs\/\nchown ubuntu:ubuntu \/home\/ubuntu\/certs\/*.pem<\/pre>\n<p>2. Pull-Type Synchronization Script on the Home Side (copy_ssl_sync.sh)<br \/>\nWe specify the private key (id_rsa) and fetch the files using rsync while following symbolic links (-L). Additionally, we incorporated logic to compare file hash values to avoid unnecessary restarts.<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">#!\/bin\/bash\n# Configuration Area\nSSH_KEY=&quot;.\/id_rsa&quot;\nSSH_USER=&quot;ubuntu&quot;\nSSH_HOST=&quot;&amp;amp;lt;OCI_IP&amp;amp;gt;&quot;\nREMOTE_PATH=&quot;\/home\/ubuntu\/certs\/&quot;\nLOCAL_PATH=&quot;\/home\/root\/servers\/ols-docker-env\/&quot;\nOLS_CONTAINER=&quot;openlitespeed&quot;\n\n# 1. Hash value comparison\nPRE_HASH=$(md5sum ${LOCAL_PATH}fullchain.pem 2&amp;amp;gt;\/dev\/null | awk &#039;{print $1}&#039;)\n\n# 2. Execute synchronization (rsync must also be installed on the remote side)\nrsync -avL -e &quot;ssh -i ${SSH_KEY} -o StrictHostKeyChecking=no&quot; \\\n${SSH_USER}@${SSH_HOST}:${REMOTE_PATH}fullchain.pem ${LOCAL_PATH}\nrsync -avL -e &quot;ssh -i ${SSH_KEY} -o StrictHostKeyChecking=no&quot; \\\n${SSH_USER}@${SSH_HOST}:${REMOTE_PATH}privkey.pem ${LOCAL_PATH}\n\n# 3. Reload OLS only if updates occurred\nPOST_HASH=$(md5sum ${LOCAL_PATH}fullchain.pem | awk &#039;{print $1}&#039;)\nif &#x5B; &quot;$PRE_HASH&quot; != &quot;$POST_HASH&quot; ]; then\ndocker exec $OLS_CONTAINER \/usr\/local\/lsws\/bin\/lswsctrl restart\nfi<\/pre>\n<p>3. Automating via cron.d with an Emphasis on Reproducibility<br \/>\nConsidering ease of management and reproducibility, we placed the configuration file in \/etc\/cron.d\/ rather than using crontab -e.<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\"># \/etc\/cron.d\/ssl-sync\n00 03 * * * root cd \/home\/root\/servers\/ols-docker-env &amp;amp;amp;&amp;amp;amp; \/bin\/bash copy_ssl_sync.sh &amp;amp;gt;&amp;amp;gt; \/var\/log\/ssl_sync.log 2&amp;amp;gt;&amp;amp;amp;1<\/pre>\n<p>&nbsp;<\/p>\n<h2>[Conclusion] Enjoying Constraints and Taming Systems<\/h2>\n<p>By completing this automated SSL renewal setup, we successfully overcame the &#8220;constraint&#8221; of a complex network architecture using the &#8220;wisdom&#8221; of scripting.<\/p>\n<ul>\n<li>The X-Forwarded-For issue was resolved by introducing Nginx.<\/li>\n<li>The SSL renewal issue was resolved with a pull-type synchronization script.<\/li>\n<li>Operations and management were resolved through file-based management using cron.d.<\/li>\n<\/ul>\n<p>At first glance, it might look like a roundabout architecture, but facing each challenge head-on and deriving solutions with one&#8217;s own hands is the very embodiment of the rich imagination and inquisitive spirit that &#8220;Nando Kobo&#8221; holds dear.<\/p>\n<p>Now, we can finally dive back into our next DIY project or technical verification with peace of mind.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The server architecture of our blog, &#8220;Nando Kobo,&#8221; has evolved into its current form after overcom [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":2500,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_locale":"en_US","_original_post":"https:\/\/donguri3.net\/?p=2498","footnotes":""},"categories":[1170],"tags":[9,18,16,15,63,20,13,14,92,10,659,1040,131],"class_list":["post-5299","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-linux-server-network","tag-diy","tag-docker","tag-lets-encrypt","tag-litespeed","tag-nginx","tag-oci","tag-ols","tag-openlitespeed","tag-wireguard","tag-server","tag-659","tag-1040","tag-131","en-US"],"_links":{"self":[{"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/posts\/5299","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/comments?post=5299"}],"version-history":[{"count":1,"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/posts\/5299\/revisions"}],"predecessor-version":[{"id":5302,"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/posts\/5299\/revisions\/5302"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/media\/2500"}],"wp:attachment":[{"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/media?parent=5299"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/categories?post=5299"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/donguri3.net\/wp-json\/wp\/v2\/tags?post=5299"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}