<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: John Cheng</title>
    <description>The latest articles on DEV Community by John Cheng (@z_zt).</description>
    <link>https://dev.to/z_zt</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1213654%2F496325d6-b2af-4abb-b6df-bb5960871d41.jpg</url>
      <title>DEV Community: John Cheng</title>
      <link>https://dev.to/z_zt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/z_zt"/>
    <language>en</language>
    <item>
      <title>Fighting Wildfires with IoT and AI: A Father-Son Open Source Mission</title>
      <dc:creator>John Cheng</dc:creator>
      <pubDate>Sat, 05 Sep 2026 05:28:39 +0000</pubDate>
      <link>https://dev.to/z_zt/fighting-wildfires-with-iot-and-ai-a-father-son-open-source-mission-4ech</link>
      <guid>https://dev.to/z_zt/fighting-wildfires-with-iot-and-ai-a-father-son-open-source-mission-4ech</guid>
      <description>&lt;h2&gt;
  
  
  🌲 Falling in Love with Nature—and Facing Wildfires
&lt;/h2&gt;

&lt;p&gt;A while ago, my family and I moved to Canada. &lt;/p&gt;

&lt;p&gt;Coming from a bustling industrial background in China, the first thing that struck us was the raw, breathtaking nature. The air is crisp, the lakes and tap water are crystal clear, and humans live side-by-side with wildlife in total harmony. In fact, in our quiet neighborhood, black bears occasionally drop by! They wander through the yard looking for berries or fallen apples, and then quietly move on without ever disrupting our daily routine.&lt;/p&gt;

&lt;p&gt;It felt like paradise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Except for one devastating problem that returns every summer: wildfires.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Year after year, millions of hectares of majestic forests are consumed by roaring fires. Smoke blankets the skies for hundreds of miles, turning the sun into an eerie orange disc, shutting down schools, and forcing families to evacuate.&lt;/p&gt;

&lt;p&gt;Watching this repeat year after year broke our hearts. We asked ourselves: &lt;em&gt;Can we use technology to make a difference before fires rage out of control?&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🤝 The Father &amp;amp; Son Team: IoT Meets Computer Vision
&lt;/h2&gt;

&lt;p&gt;I have spent decades working in &lt;strong&gt;industrial IoT hardware and embedded systems&lt;/strong&gt; in China—designing rugged field sensors, remote telemetry units, and ultra-reliable communications. &lt;/p&gt;

&lt;p&gt;Meanwhile, my son is currently studying &lt;strong&gt;Computer Science with a focus on Artificial Intelligence and Computer Vision&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One evening, looking out at the haze during wildfire season, we had an idea: &lt;strong&gt;What if we combined our strengths?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Father (Edge Hardware &amp;amp; Firmware):&lt;/strong&gt; Build an ultra-reliable, off-grid, low-power IoT sensing node capable of surviving years in remote wilderness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Son (Cloud Backend &amp;amp; Multi-Modal AI):&lt;/strong&gt; Ingest real-time telemetry, filter sensor drift, and run lightweight AI vision models on remote camera snapshots to verify smoke columns and suppress false alarms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is how &lt;strong&gt;ForestFireGuard&lt;/strong&gt; was born.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎥 The Story in Video
&lt;/h2&gt;

&lt;p&gt;I recently recorded a short video sharing our journey, our motivation, and why we decided to make this project 100% open source:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/EVP5XfrIreA" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(If the embed doesn't load, you can watch it directly &lt;a href="https://youtu.be/EVP5XfrIreA" rel="noopener noreferrer"&gt;on YouTube&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ The Engineering Challenge: Why Wildfire IoT is Hard
&lt;/h2&gt;

&lt;p&gt;Building a wildfire detector for a warm living room is easy. Building one for an isolated boreal forest is an entirely different engineering beast:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Zero External Power:&lt;/strong&gt; The node must run off a single primary battery and small solar cells for years.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fragile Cellular Connectivity:&lt;/strong&gt; In deep forests, 4G signals fluctuate or drop for days. &lt;strong&gt;Zero data loss&lt;/strong&gt; is mandatory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Severe Hardware RAM Constraints:&lt;/strong&gt; Running on low-cost, low-power microcontrollers (STM32F030 with only 32KB SRAM) means you cannot allocate massive memory buffers for camera image payloads without risking stack overflows or fragmentation.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🏗️ How ForestFireGuard Works
&lt;/h2&gt;

&lt;p&gt;Here is a look at the system architecture we engineered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-----------------------------------------------------------------------------------+
|                            EDGE NODE SUBSYSTEM (mcu/)                             |
|                                                                                   |
|  +--------------------+         +---------------------+                           |
|  | ESP32 Camera Node  |--UART--&amp;gt;|  SPI RAM (64KB)     | (High-Speed Image Cache)  |
|  | (VGA 640x480 JPEG) |         +----------+----------+                           |
|  +--------------------+                    |                                      |
|                                            v                                      |
|  +--------------------+         +---------------------+         +--------------+  |
|  |  Primary Sensors   |--I2C/--&amp;gt;|  SPI Flash (1MB)    |&amp;lt;--FRAM--|  Mainboard   |  |
|  | (GPS, AQ, Temp/Humi|  ADC    | (Append-Only Queue) |  (8KB)  | (STM32F030)  |  |
|  +--------------------+         +----------+----------+         +-------+------+  |
|                                            |                            |         |
+--------------------------------------------|----------------------------|---------+
                                             v                            | TLV
                                  +---------------------+                 v
                                  |   Network Module    |&amp;lt;----------------+
                                  | (EC800CN 4G Cat.1)  |
                                  +----------+----------+
                                             |
                                    MQTT / TCP Cellular
                                             v
+-----------------------------------------------------------------------------------+
|                        SERVER &amp;amp; AI SUBSYSTEM (service/ &amp;amp; Cloud)                   |
|                                                                                   |
|  +-----------------------------------------------------------------------------+  |
|  |                       IoT Ingress Service (service/)                        |  |
|  |                     (Receives 4G Payload &amp;amp; Stores to DB)                    |  |
|  +--------------------------------------+--------------------------------------+  |
|                                         |                                         |
|  =======================================|=======================================  |
|                 DATABASE LAYER (Delivery &amp;amp; Separation Boundary)                   |
|  =======================================|=======================================  |
|                                         v                                         |
|  +-----------------------------------------------------------------------------+  |
|  |                   Cloud AI Engine (Son's Pipeline)                          |  |
|  |  * Fetches real-time sensor metrics &amp;amp; VGA photos from DB                   |  |
|  |  * Runs Lightweight CV models (Smoke &amp;amp; Flame detection)                    |  |
|  |  * Dispatches verified high-confidence alerts to emergency channels        |  |
|  +-----------------------------------------------------------------------------+  |
+-----------------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Technical Highlights:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;3-Tier Storage for Zero Data Loss:&lt;/strong&gt; 

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;64KB SPI RAM&lt;/strong&gt; caches incoming JPEG images from the ESP32 camera without touching the STM32's tiny 32KB internal SRAM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1MB SPI Flash&lt;/strong&gt; operates in append-only mode as an indestructible flight data recorder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;8KB Ferroelectric RAM (FRAM)&lt;/strong&gt; records non-volatile read/write pointers with near-infinite endurance. If the battery dies or connection drops, transmission resumes seamlessly upon reboot.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-Multiplexed Power Gating:&lt;/strong&gt; All power-hungry modules (4G modem, camera, gas sensors) sit behind independent MOSFET switches. The STM32 powers them on sequentially, preventing destructive peak current surges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean Architecture Boundary:&lt;/strong&gt; The PostgreSQL/Timescale database serves as the strict contract boundary. I ensure rock-solid data ingestion from the field into the DB; my son pulls from the DB for AI training, validation, and real-time inference.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🌍 Why We Are Making It 100% Open Source
&lt;/h2&gt;

&lt;p&gt;Wildfires don't respect borders or patents. Communities in Canada, the US, Southern Europe, Australia, and South America are all battling the same threat.&lt;/p&gt;

&lt;p&gt;We believe that by sharing our schematics, PCB gerbers, STM32 firmware, and cloud code with the global developer community, we can help local forestry teams, researchers, and volunteers deploy affordable, early-warning sensor meshes.&lt;/p&gt;

&lt;h3&gt;
  
  
  💻 Join Us on GitHub!
&lt;/h3&gt;

&lt;p&gt;The project source code is available now on GitHub:&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://github.com/Snowy-Collie/ForestGuardCloud" rel="noopener noreferrer"&gt;Check out AI part on GitHub (Alex)&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://github.com/wezhike/ForestFireGuard" rel="noopener noreferrer"&gt;Check out Hardware on GitHub(John)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We would love to hear your feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What sensors would you prioritize for forest deployment?&lt;/li&gt;
&lt;li&gt;Have you tackled similar memory and power constraints on Cortex-M0 devices?&lt;/li&gt;
&lt;li&gt;Want to help with PCB design, embedded C refactoring, or computer vision models?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Drop a comment below or open an issue on GitHub. Let’s build technology that makes a real-world difference together! 🌲🔥🚒&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>iot</category>
      <category>ai</category>
      <category>hardware</category>
    </item>
    <item>
      <title>Building an Images Repository - Harbor</title>
      <dc:creator>John Cheng</dc:creator>
      <pubDate>Sun, 19 Nov 2023 13:53:59 +0000</pubDate>
      <link>https://dev.to/z_zt/building-a-harbor-repository-m16</link>
      <guid>https://dev.to/z_zt/building-a-harbor-repository-m16</guid>
      <description>&lt;p&gt;Harbor is designed for storing container images and is generally deployed in an intranet environment to provide image services for containers running within the intranet.&lt;/p&gt;

&lt;p&gt;Harbor is open source and can be found on GitHub at: &lt;a href="https://github.com/goharbor/harbor" rel="noopener noreferrer"&gt;https://github.com/goharbor/harbor&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Testing Environment
&lt;/h2&gt;

&lt;p&gt;For testing purposes, set up a new virtual machine with CentOS 7.9 and make some modifications to the test environment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Disable the firewall, install iptables, and temporarily disable it:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl stop firewalld
systemctl disable firewalld
yum &lt;span class="nb"&gt;install &lt;/span&gt;iptables-services &lt;span class="nt"&gt;-y&lt;/span&gt;
systemctl stop iptables
systemctl disable iptables
iptables &lt;span class="nt"&gt;-F&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Disable SELinux:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;setenforce 0
&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/SELINUX=enforcing/SELINUX=disabled/g'&lt;/span&gt; /etc/selinux/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Synchronize system time:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ntpdata cn.pool.ntp.org
crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Insert the following entry to synchronize every hour:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;/1 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /usr/sbin/ntpdate cn.pool.ntp.org
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install common components:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yum &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; yum-utils device-mapper-persistent-data lvm2 wget net-tools nfs-utils lrzsz gcc gcc-c++ make cmake libxml2-devel openssl-devel curl curl-devel unzip &lt;span class="nb"&gt;sudo &lt;/span&gt;ntp libaio-devel vim ncurses-devel autoconf automake zlib-devel python-devel epel-release openssh-server socat ipvsadm conntrack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Set up the repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Enable system forwarding:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"net.bridge.bridge-nf-call-ip6tables = 1"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/sysctl.conf
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"net.bridge.bridge-nf-call-iptables = 1"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/sysctl.conf
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"net.ipv4.ip_forward = 1"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; /etc/sysctl.conf
sysctl &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Install Docker and Download Docker Compose
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install the latest version of Docker:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yum &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; docker-ce
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Enable Docker:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;docker &lt;span class="nt"&gt;--now&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Download Docker Compose:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://github.com/docker/compose/releases/download/v2.23.1/docker-compose-linux-x86_64
&lt;span class="nb"&gt;mv &lt;/span&gt;docker-compose-linux-x86_64 /usr/bin/docker-compose
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x /usr/bin/docker-compose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Create Certificates
&lt;/h2&gt;

&lt;p&gt;During the certificate creation process, ensure consistency in country code and city code. The hostname must match the local machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /data/ssl &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /data/ssl/
openssl genrsa &lt;span class="nt"&gt;-out&lt;/span&gt; ca.key 3072
openssl req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 3650 &lt;span class="nt"&gt;-key&lt;/span&gt; ca.key &lt;span class="nt"&gt;-out&lt;/span&gt; ca.pem
openssl genrsa &lt;span class="nt"&gt;-out&lt;/span&gt; harbor.key 3072
openssl req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-key&lt;/span&gt; harbor.key &lt;span class="nt"&gt;-out&lt;/span&gt; harbor.csr
openssl x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; harbor.csr &lt;span class="nt"&gt;-CA&lt;/span&gt; ca.pem &lt;span class="nt"&gt;-CAkey&lt;/span&gt; ca.key &lt;span class="nt"&gt;-CAcreateserial&lt;/span&gt; &lt;span class="nt"&gt;-out&lt;/span&gt; harbor.pem &lt;span class="nt"&gt;-days&lt;/span&gt; 3650
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Download and Install Harbor
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a directory:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /data/install
&lt;span class="nb"&gt;cd&lt;/span&gt; /data/install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Download and extract files:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://github.com/goharbor/harbor/releases/download/v2.3.0-rc3/harbor-offline-installer-v2.3.0-rc3.tgz
&lt;span class="nb"&gt;tar &lt;/span&gt;zxvf harbor-offline-installer-v2.3.0-rc3.tgz &lt;span class="nt"&gt;-C&lt;/span&gt; /data/install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Modify the configuration file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; /data/install/harbor/harbor.yml.tmpl /data/install/harbor/harbor.yml
vim /data/install/harbor/harbor.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modify the hostname, certificate, and private_key to actual values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;: harbor &lt;span class="c"&gt;# Adjust as needed&lt;/span&gt;

certificate: /data/ssl/harbor.pem
private_key: /data/ssl/harbor.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install Harbor:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/data/install/harbor/install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Web User Management on the Client
&lt;/h2&gt;

&lt;p&gt;Access the IP or domain of this host to open the login page. Initial admin account information: &lt;br&gt;
Username: admin&lt;br&gt;
Password: Harbor12345&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 6: Configure Docker on the Client
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Modify /etc/docker/daemon.json:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vim /etc/docker/daemon.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Add the following field in the client machine's /etc/docker/daemon.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;insecure-registries&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;192.168.xxx.xxx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hostname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Restart the Docker service:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl daemon-reload
systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Testing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Upload Test: Tag the image on the local machine in the format: ip/project_name/image_name
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker tag tomcat:latest 192.168.xxx.xxx/test/tomcat:v1
docker push 192.168.xxx.xxx/test/tomcat:v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Download Test:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull 192.168.xxx.xxx/test/tomcat:v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>image</category>
      <category>docker</category>
      <category>k8s</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Building a Private Repository</title>
      <dc:creator>John Cheng</dc:creator>
      <pubDate>Sun, 19 Nov 2023 13:50:55 +0000</pubDate>
      <link>https://dev.to/z_zt/building-an-intranet-sync-source-3a3b</link>
      <guid>https://dev.to/z_zt/building-an-intranet-sync-source-3a3b</guid>
      <description>&lt;p&gt;In the architecture of cloud services, multiple network planes are generally deployed, and the management plane is usually in the intranet environment, accessible through a jump server or VPN technology. This brings significant inconvenience to the installation, upgrade, or system upgrade of applications for the infrastructure of the server. Today, I will introduce a simple method to build a self-built Linux private repository.&lt;/p&gt;

&lt;p&gt;Before we begin, you need to prepare a virtual host with dual network cards, or a physical host will work as well. The host should run the Linux operating system; here, we'll use CentOS 7.9 as an example. If you are using a Debian-based Linux system, just replace the commands with &lt;code&gt;apt&lt;/code&gt; commands; the principle is exactly the same.&lt;/p&gt;

&lt;p&gt;Once the system is installed, connect one network card to the external network and another to the intranet, complete the relevant configurations and tests. Now let's officially start building the private repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Install and Configure Nginx
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Install Nginx
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a basic operation, and installing Nginx may require additional steps, such as installing the EPEL repository. If you encounter any issues installing Nginx, please search online for related tutorials.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure Nginx
&lt;/h3&gt;

&lt;p&gt;Configuring Nginx is straightforward. Just add three lines under the &lt;code&gt;server&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vim /etc/nginx/nginx.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    server &lt;span class="o"&gt;{&lt;/span&gt;
        autoindex on&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c"&gt;# Add this line&lt;/span&gt;
        autoindex_exact_size on&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c"&gt;# Add this line&lt;/span&gt;
        autoindex_localtime on&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c"&gt;# Add this line&lt;/span&gt;
        listen       80&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c"&gt;# Listening port&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then restart Nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Create a Directory for Sync
&lt;/h2&gt;

&lt;p&gt;This directory is configured in the /etc/nginx/nginx.conf file from the previous step. Here, we create it in the default working directory of Nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /usr/share/nginx/html/rsync/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Download Sources
&lt;/h2&gt;

&lt;p&gt;You can download applications individually or synchronize downloads in batches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Download a Single Application
&lt;/h3&gt;

&lt;p&gt;As an example, let's download haproxy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /usr/share/nginx/html/rsync/haproxy
&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--downloadonly&lt;/span&gt; &lt;span class="nt"&gt;--downloaddir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/share/nginx/html/rsync/haproxy/ haproxy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: This method downloads only applications that have not been installed on the local machine before. If you try to download an application that has been previously installed, such as nginx, you will get nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Batch Download
&lt;/h3&gt;

&lt;p&gt;Here we use the EPEL repository as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p /usr/share/nginx/html/rsync/epel/7/x86_64/
rsync -vrt --bwlimit=3000 --exclude=debug/ rsync://rsync.mirrors.ustc.edu.cn/epel/7/x86_64/ /usr/share/nginx/html/rsync/epel/7/x86_64/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create an Index
&lt;/h3&gt;

&lt;p&gt;When creating the index for the first time, install &lt;code&gt;createrepo&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; createrepo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the index; you need to use this command every time you update the content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;createrepo /usr/share/nginx/html/rsync/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;After these steps, the sync source is successfully installed. On the intranet host, modify the repo file's &lt;code&gt;baseurl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;baseurl &lt;span class="o"&gt;=&lt;/span&gt; http://xxx.xxx.xxx.xxx/rsync
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, transfer it to the relevant host and install using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;yum &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; http://xxx.xxx.xxx.xxx/rsync/haproxy/haproxy-1.5.18-9.el7_9.1.x86_64.rpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>repo</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
