<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Operations on KnightLi Blog</title>
        <link>https://knightli.com/en/categories/operations/</link>
        <description>Recent content in Operations on KnightLi Blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en</language>
        <lastBuildDate>Sat, 30 May 2026 16:14:19 +0800</lastBuildDate><atom:link href="https://knightli.com/en/categories/operations/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Sync Local Markdown Notes with a Self-Hosted Git Server on a NAS</title>
        <link>https://knightli.com/en/2026/05/30/nas-git-server-local-notes-sync/</link>
        <pubDate>Sat, 30 May 2026 16:14:19 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/05/30/nas-git-server-local-notes-sync/</guid>
        <description>&lt;p&gt;If you already have a local NAS and want to keep your notes as much as possible under your own control, you can put Markdown notes into a Git Server on the NAS and sync them with Android and Windows clients. This setup does not depend on public cloud drives, and it works well with note tools centered on local Markdown files, such as Obsidian, Markor, VS Code, and Typora.&lt;/p&gt;
&lt;p&gt;The basic idea is simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a bare Git repository on the NAS as the central notes repository.&lt;/li&gt;
&lt;li&gt;Clone the repository on Windows and write notes with a normal editor.&lt;/li&gt;
&lt;li&gt;Clone the same repository on Android and use a Git client to pull and push.&lt;/li&gt;
&lt;li&gt;Before switching devices, run &lt;code&gt;pull&lt;/code&gt;; after writing, run &lt;code&gt;commit&lt;/code&gt; and &lt;code&gt;push&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is not the most hands-off sync method, but it gives good control and clear version history. Once you build the habit of committing, you can keep notes, configuration, and image attachments on your own NAS for long-term storage.&lt;/p&gt;
&lt;h2 id=&#34;who-this-setup-is-for&#34;&gt;Who This Setup Is For
&lt;/h2&gt;&lt;p&gt;This setup is suitable for people who:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Already have a NAS at home or in the office.&lt;/li&gt;
&lt;li&gt;Mainly write notes as Markdown files.&lt;/li&gt;
&lt;li&gt;Want note data stored inside a local network instead of only on a commercial cloud drive.&lt;/li&gt;
&lt;li&gt;Need sync between Windows and Android devices.&lt;/li&gt;
&lt;li&gt;Can accept basic Git operations such as &lt;code&gt;clone&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, &lt;code&gt;commit&lt;/code&gt;, and &lt;code&gt;push&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want fully automatic and invisible sync, Syncthing, WebDAV, or the built-in sync of a notes app may be easier. Git is better for a notes library where version history, rollback, migration, and control matter.&lt;/p&gt;
&lt;h2 id=&#34;1-install-git-server-on-the-nas&#34;&gt;1. Install Git Server on the NAS
&lt;/h2&gt;&lt;p&gt;Different NAS systems expose this in different places, but the goal is the same: let the NAS provide a Git repository that can be accessed through SSH.&lt;/p&gt;
&lt;p&gt;There are three common approaches:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Method&lt;/th&gt;
          &lt;th&gt;Suitable Scenario&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Install Git Server from the NAS package center&lt;/td&gt;
          &lt;td&gt;Synology, QNAP, and other consumer NAS systems when you want less setup work&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Deploy Gitea with Docker&lt;/td&gt;
          &lt;td&gt;You want a web UI, account management, and a more complete Git service&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Use SSH + a bare repository directly&lt;/td&gt;
          &lt;td&gt;You only use it yourself and want something simple and stable&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For personal note sync, SSH + a bare repository is usually enough. Suppose the NAS has a dedicated Git user named &lt;code&gt;git&lt;/code&gt;, and repositories are stored under &lt;code&gt;/volume1/git&lt;/code&gt;. On the NAS terminal, run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p /volume1/git/notes.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /volume1/git/notes.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git init --bare
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;A bare repository is not edited directly. It only acts as the sync center. The actual note-writing directory lives locally on Windows or Android.&lt;/p&gt;
&lt;p&gt;Then confirm that SSH can access the NAS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh git@192.168.1.10
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If the NAS supports SSH public-key login, configure keys so you do not need to enter a password every time you push. Windows and Android can each generate their own SSH key, and then you can add the public keys to the NAS &lt;code&gt;authorized_keys&lt;/code&gt; file or the Git Server user settings.&lt;/p&gt;
&lt;h2 id=&#34;2-windows-setup&#34;&gt;2. Windows Setup
&lt;/h2&gt;&lt;p&gt;On Windows, install Git for Windows first. Then choose a local directory for notes, such as &lt;code&gt;D:\Notes&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Initial clone:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clone&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;git&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;@192&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;168&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;volume1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;notes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;D:&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Notes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;After entering the directory, you can create a basic structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;D:&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Notes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;mkdir&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;inbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;daily&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;projects&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;resources&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then open &lt;code&gt;D:\Notes&lt;/code&gt; with Obsidian, VS Code, Typora, or another Markdown editor. After writing the first batch of notes, commit them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;commit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;-m&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;初始化笔记库&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;origin&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If the default branch is &lt;code&gt;master&lt;/code&gt;, replace &lt;code&gt;main&lt;/code&gt; with &lt;code&gt;master&lt;/code&gt; in the command. You can also standardize it to &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;branch&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;-M&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;-u&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;origin&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For daily use, keep this rhythm on Windows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pull&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;-rebase&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;commit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;-m&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;更新笔记&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;push&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;3-android-setup&#34;&gt;3. Android Setup
&lt;/h2&gt;&lt;p&gt;On Android, use a client that supports Git to sync the local Markdown directory. Common choices include:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Tool&lt;/th&gt;
          &lt;th&gt;Usage&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Termux&lt;/td&gt;
          &lt;td&gt;Most flexible, close to a Linux command line&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;MGit&lt;/td&gt;
          &lt;td&gt;Graphical Git client, suitable if you do not want to type many commands&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;GitJournal&lt;/td&gt;
          &lt;td&gt;More like a notes app, suitable for simple Markdown notes&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If you choose Termux, first install Git and OpenSSH:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pkg update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pkg install git openssh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Generate an SSH key:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ssh-keygen -t ed25519 -C &lt;span class=&#34;s2&#34;&gt;&amp;#34;android-notes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Add the generated public key to the Git user authorization on the NAS. Then choose a local directory on the phone and clone the repository:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone git@192.168.1.10:/volume1/git/notes.git ~/notes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If you want ordinary Android editors to access this directory, you can put the repository in shared storage, for example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /sdcard
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone git@192.168.1.10:/volume1/git/notes.git Notes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then open &lt;code&gt;/sdcard/Notes&lt;/code&gt; with Markor, Obsidian Android, or another Markdown editor. After editing on the phone, return to Termux and run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /sdcard/Notes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git pull --rebase
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git add .
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git commit -m &lt;span class=&#34;s2&#34;&gt;&amp;#34;手机更新笔记&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git push
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Permissions and paths are the easiest sources of trouble on Android. Termux&amp;rsquo;s own home directory is more stable, but some editors may not access it directly. &lt;code&gt;/sdcard&lt;/code&gt; is easier for editors to access, but permissions, file watching, and performance may be limited by the system. Test with a small number of notes before deciding on the final directory.&lt;/p&gt;
&lt;h2 id=&#34;4-how-obsidian-and-joplin-fit-in&#34;&gt;4. How Obsidian and Joplin Fit In
&lt;/h2&gt;&lt;p&gt;The NAS Git Server only solves where files live and how they sync. You still need to choose a notes app for writing. Here, the setup can be split into an Obsidian path and a Joplin path.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Setup&lt;/th&gt;
          &lt;th&gt;Sync Method&lt;/th&gt;
          &lt;th&gt;Best For&lt;/th&gt;
          &lt;th&gt;Notes&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Obsidian + Git&lt;/td&gt;
          &lt;td&gt;The notes directory is the Git repository, and Windows and Android both pull the same repository&lt;/td&gt;
          &lt;td&gt;People who want backlinks, knowledge graphs, plugins, and pure Markdown files&lt;/td&gt;
          &lt;td&gt;On Android, test whether the Git client and Obsidian can access the same directory correctly&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Joplin + Git&lt;/td&gt;
          &lt;td&gt;Do not put the Joplin database directly into Git; use Joplin&amp;rsquo;s own sync or export Markdown to Git regularly&lt;/td&gt;
          &lt;td&gt;People who want web clipping, end-to-end encryption, and a traditional notebook structure&lt;/td&gt;
          &lt;td&gt;Joplin&amp;rsquo;s local data is not a normal Markdown folder and is not suitable as a direct Git-synced notes library&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;obsidian-setup&#34;&gt;Obsidian Setup
&lt;/h3&gt;&lt;p&gt;Obsidian is the best fit for this NAS Git sync setup. Its vault is essentially an ordinary folder containing Markdown files, image attachments, and configuration files. You can directly use &lt;code&gt;D:\Notes&lt;/code&gt; or &lt;code&gt;/sdcard/Notes&lt;/code&gt; as the Obsidian vault.&lt;/p&gt;
&lt;p&gt;Windows workflow:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clone&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;git&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;@192&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;168&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;volume1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;notes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;py&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;D:&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Notes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then open &lt;code&gt;D:\Notes&lt;/code&gt; in Obsidian.&lt;/p&gt;
&lt;p&gt;Android workflow:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /sdcard
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone git@192.168.1.10:/volume1/git/notes.git Notes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then open &lt;code&gt;/sdcard/Notes&lt;/code&gt; in Obsidian Android.&lt;/p&gt;
&lt;p&gt;Suggestions for the Obsidian setup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For single-user use, you can commit &lt;code&gt;.obsidian/&lt;/code&gt; so themes, plugins, and some settings sync across devices.&lt;/li&gt;
&lt;li&gt;If Android and Windows use very different plugins, commit only the note content and exclude device-state files such as &lt;code&gt;.obsidian/workspace.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Put image attachments under &lt;code&gt;attachments/&lt;/code&gt; to avoid scattering them across directories.&lt;/li&gt;
&lt;li&gt;Before opening Obsidian, run &lt;code&gt;git pull --rebase&lt;/code&gt;; after writing, run &lt;code&gt;commit&lt;/code&gt; and &lt;code&gt;push&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can prepare a &lt;code&gt;.gitignore&lt;/code&gt; to reduce conflicts caused by device-state files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.obsidian/workspace.json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.obsidian/workspace-mobile.json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.trash/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id=&#34;joplin-setup&#34;&gt;Joplin Setup
&lt;/h3&gt;&lt;p&gt;Joplin works differently from Obsidian. Although it uses Markdown syntax, its local data is mainly managed by the application&amp;rsquo;s database. It is not a normal Markdown folder that can be synced directly with Git. Therefore, do not put Joplin&amp;rsquo;s configuration or database directory directly into a Git repository.&lt;/p&gt;
&lt;p&gt;If you prefer Joplin, two safer approaches are:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Approach&lt;/th&gt;
          &lt;th&gt;Description&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Use Joplin&amp;rsquo;s built-in sync&lt;/td&gt;
          &lt;td&gt;Sync through WebDAV, Nextcloud, Joplin Cloud, Dropbox, OneDrive, and similar options. The NAS can provide WebDAV or Nextcloud&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Export Markdown to Git regularly&lt;/td&gt;
          &lt;td&gt;Use Joplin as the main notes app, regularly export notes as Markdown, and commit them to the NAS Git repository as a backup&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If your NAS already has WebDAV or Nextcloud, connecting Joplin directly to the NAS for sync is smoother than Git. It can also enable end-to-end encryption, which is suitable for people who do not want to handle Git conflicts but still want data under their own control.&lt;/p&gt;
&lt;p&gt;The recommended Joplin + NAS path is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enable WebDAV on the NAS or deploy Nextcloud.&lt;/li&gt;
&lt;li&gt;Configure the same sync target on Joplin for Windows.&lt;/li&gt;
&lt;li&gt;Configure the same sync target on Joplin for Android.&lt;/li&gt;
&lt;li&gt;When versioned backup is needed, export Markdown to the Git repository regularly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Simple rule of thumb:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Choose Obsidian if you want &amp;ldquo;local Markdown folder + backlinks + Git history&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Choose Joplin if you want &amp;ldquo;traditional notes app + web clipping + encrypted sync&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;If you want the NAS Git Server as the main sync center, Obsidian is more suitable.&lt;/li&gt;
&lt;li&gt;If you want the NAS to act as a private cloud sync backend, Joplin is more suitable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;5-recommended-notes-directory-structure&#34;&gt;5. Recommended Notes Directory Structure
&lt;/h2&gt;&lt;p&gt;Do not design the notes library too elaborately at the beginning. Start with a structure like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Notes/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  inbox/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  daily/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  projects/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  resources/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  attachments/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  README.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The meaning is straightforward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;inbox/&lt;/code&gt; stores temporary notes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;daily/&lt;/code&gt; stores journals, logs, and daily records.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;projects/&lt;/code&gt; stores project notes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resources/&lt;/code&gt; stores long-term reference material.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;attachments/&lt;/code&gt; stores images, PDFs, and other attachments.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you use Obsidian, you can use this directory directly as a vault. Whether to commit &lt;code&gt;.obsidian/&lt;/code&gt; depends on personal preference. For single-user multi-device use, committing it is fine. If plugins differ greatly across devices, commit only part of the configuration.&lt;/p&gt;
&lt;h2 id=&#34;6-avoiding-sync-conflicts&#34;&gt;6. Avoiding Sync Conflicts
&lt;/h2&gt;&lt;p&gt;The key to syncing notes with Git is not complicated commands, but stable habits.&lt;/p&gt;
&lt;p&gt;Recommended rules:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Before writing on another device, run &lt;code&gt;git pull --rebase&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;After a writing session, run &lt;code&gt;commit&lt;/code&gt; and &lt;code&gt;push&lt;/code&gt; promptly.&lt;/li&gt;
&lt;li&gt;Do not edit the same file on two devices for a long time at the same time.&lt;/li&gt;
&lt;li&gt;Do not keep adding unlimited images and large attachments into the Git repository.&lt;/li&gt;
&lt;li&gt;Regularly keep another backup of the repository outside the NAS.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If a conflict happens, Git will mark the conflicting files. Markdown text conflicts are usually not hard to resolve, but the experience is worse on a phone, so try to resolve conflicts on Windows.&lt;/p&gt;
&lt;h2 id=&#34;7-do-you-need-automatic-sync&#34;&gt;7. Do You Need Automatic Sync?
&lt;/h2&gt;&lt;p&gt;You can write a simple Windows script that chains &lt;code&gt;pull&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;commit&lt;/code&gt;, and &lt;code&gt;push&lt;/code&gt;. But for note sync, fully automatic commits are not recommended, because accidental deletions, empty commits, conflicts, and large attachments may all be pushed automatically.&lt;/p&gt;
&lt;p&gt;A safer approach is semi-automatic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pull manually before opening notes.&lt;/li&gt;
&lt;li&gt;Run a script to commit after writing.&lt;/li&gt;
&lt;li&gt;Use a simple commit message that says what changed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, you can prepare a &lt;code&gt;sync-notes.ps1&lt;/code&gt; on Windows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-powershell&#34; data-lang=&#34;powershell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pull&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;-rebase&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;add&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;commit&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;-m&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;更新笔记&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;git&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;push&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If there are no changes, &lt;code&gt;git commit&lt;/code&gt; will report nothing to commit. That is not a problem.&lt;/p&gt;
&lt;h2 id=&#34;8-pros-and-cons-of-this-setup&#34;&gt;8. Pros and Cons of This Setup
&lt;/h2&gt;&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Aspect&lt;/th&gt;
          &lt;th&gt;Description&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Pros&lt;/td&gt;
          &lt;td&gt;Data stays on the local NAS, version history is clear, rollback is possible, migration is easy, and it suits Markdown&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Cons&lt;/td&gt;
          &lt;td&gt;Requires understanding Git, conflicts need manual handling, and the mobile experience is not as smooth as cloud sync&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Best for&lt;/td&gt;
          &lt;td&gt;Technical users, local-first notes, personal knowledge bases, project documentation&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Not for&lt;/td&gt;
          &lt;td&gt;People who do not want to touch a command line, need real-time multi-user collaboration, or frequently sync large attachments&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;my-recommendation&#34;&gt;My Recommendation
&lt;/h2&gt;&lt;p&gt;If you only want to sync ordinary Markdown notes between Android and Windows, start with the smallest setup: one bare repository on the NAS, Git for Windows on Windows, and Termux or MGit on Android. Do not introduce complex permissions, automation scripts, or excessive categorization on day one.&lt;/p&gt;
&lt;p&gt;After this workflow runs smoothly, then consider Gitea, automatic backups, per-device SSH key management, a separate attachment repository, scheduled tasks, and other extensions. The most important thing for a notes system is long-term stability, not filling it with every feature on the first day.&lt;/p&gt;
&lt;p&gt;In one sentence: a NAS Git Server is suitable for turning Markdown notes into a local-first, traceable, and portable personal knowledge library. It is less effortless than cloud sync, but the control is clearer.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Choosing a Linux Server Distribution in 2026: Debian, Rocky Linux, AlmaLinux, and Ubuntu Server Compared</title>
        <link>https://knightli.com/en/2026/05/07/linux-server-distro-comparison-2026/</link>
        <pubDate>Thu, 07 May 2026 21:03:12 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/05/07/linux-server-distro-comparison-2026/</guid>
        <description>&lt;p&gt;When choosing a Linux server distribution in 2026, the key question is not &amp;ldquo;which one is best,&amp;rdquo; but &amp;ldquo;which one fits your operations model.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;If you need the most stable community distribution, Debian remains one of the best choices. If you need the RHEL-compatible ecosystem but do not want to buy RHEL directly, Rocky Linux and AlmaLinux are the most natural CentOS successors. If you care most about cloud images, documentation, fast deployment, and newer packages, Ubuntu Server is still the easiest path.&lt;/p&gt;
&lt;p&gt;Below is a practical comparison from a server perspective.&lt;/p&gt;
&lt;h2 id=&#34;quick-conclusion&#34;&gt;Quick Conclusion
&lt;/h2&gt;&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Distribution&lt;/th&gt;
          &lt;th&gt;Best For&lt;/th&gt;
          &lt;th&gt;Main Strengths&lt;/th&gt;
          &lt;th&gt;Main Notes&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Debian&lt;/td&gt;
          &lt;td&gt;Long-term stability, self-hosting, basic services&lt;/td&gt;
          &lt;td&gt;Stable, clean, strong community, deep free-software tradition&lt;/td&gt;
          &lt;td&gt;Default packages are conservative; enterprise commercial support is less explicit than RHEL/Ubuntu&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Rocky Linux&lt;/td&gt;
          &lt;td&gt;RHEL-compatible production environments&lt;/td&gt;
          &lt;td&gt;Close to RHEL habits, suitable for enterprise CentOS migration&lt;/td&gt;
          &lt;td&gt;Conservative package cadence; desktop and new-tech experience are not the focus&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;AlmaLinux&lt;/td&gt;
          &lt;td&gt;RHEL-compatible production, cloud, enterprise replacement&lt;/td&gt;
          &lt;td&gt;RHEL compatible, active community, clear lifecycle&lt;/td&gt;
          &lt;td&gt;Still has some differences from RHEL; read release notes&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Ubuntu Server&lt;/td&gt;
          &lt;td&gt;Cloud servers, containers, development deployment&lt;/td&gt;
          &lt;td&gt;Strong cloud support, rich docs, fast deployment, long LTS lifecycle&lt;/td&gt;
          &lt;td&gt;Snap, HWE kernels, and PPAs need team-wide rules&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In one sentence:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Safest general-purpose choice&lt;/strong&gt;: Debian.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enterprise RHEL ecosystem replacement&lt;/strong&gt;: Rocky Linux / AlmaLinux.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud and development efficiency first&lt;/strong&gt;: Ubuntu Server.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;debian-rock-solid-stability&#34;&gt;Debian: Rock-Solid Stability
&lt;/h2&gt;&lt;p&gt;As of May 2026, the current Debian stable release is Debian 13 &lt;code&gt;trixie&lt;/code&gt;. Debian 12 &lt;code&gt;bookworm&lt;/code&gt; has moved into oldstable and still receives security and LTS support, but new server deployments should generally start with Debian 13.&lt;/p&gt;
&lt;p&gt;Debian&amp;rsquo;s characteristics have always been clear:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;conservative default package selection;&lt;/li&gt;
&lt;li&gt;clean system structure;&lt;/li&gt;
&lt;li&gt;no strong commercial-vendor binding;&lt;/li&gt;
&lt;li&gt;mature community governance;&lt;/li&gt;
&lt;li&gt;well suited to long-running basic services.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Debian is comfortable if your servers mainly run:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nginx / Apache;&lt;/li&gt;
&lt;li&gt;PostgreSQL / MariaDB / Redis;&lt;/li&gt;
&lt;li&gt;Docker / Podman;&lt;/li&gt;
&lt;li&gt;WireGuard / Tailscale;&lt;/li&gt;
&lt;li&gt;file services, backup services, monitoring services;&lt;/li&gt;
&lt;li&gt;small self-hosted applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Debian&amp;rsquo;s advantage is not being &amp;ldquo;the newest,&amp;rdquo; but requiring less fuss. Many servers can run for years with normal security updates and minor maintenance.&lt;/p&gt;
&lt;p&gt;Debian is suitable when:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;you want the system to stay simple and not be too affected by vendor strategy;&lt;/li&gt;
&lt;li&gt;you are familiar with &lt;code&gt;apt&lt;/code&gt;, systemd, and Debian file layout;&lt;/li&gt;
&lt;li&gt;you can accept software versions that are not the newest;&lt;/li&gt;
&lt;li&gt;you care more about stability, security updates, and predictable upgrades.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Debian is less suitable when:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;a vendor only certifies RHEL or Ubuntu;&lt;/li&gt;
&lt;li&gt;you need enterprise commercial support with an SLA;&lt;/li&gt;
&lt;li&gt;you depend on the newest kernel, GPU stack, or new hardware support;&lt;/li&gt;
&lt;li&gt;your team has already built operations standards around the RHEL ecosystem.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;My take: for personal servers, self-hosting, lightweight SaaS, and small-team infrastructure, Debian remains an excellent first choice.&lt;/p&gt;
&lt;h2 id=&#34;rocky-linux-a-steady-centos-successor&#34;&gt;Rocky Linux: A Steady CentOS Successor
&lt;/h2&gt;&lt;p&gt;Rocky Linux has a clear position: it serves users who need the RHEL-compatible ecosystem and continues the role that CentOS Linux played in enterprise production environments.&lt;/p&gt;
&lt;p&gt;In 2026, both Rocky Linux 9 and Rocky Linux 10 are within their support periods. Rocky Linux 9 fits more conservative production environments, while Rocky Linux 10 is better for new projects, newer hardware, and a longer future runway.&lt;/p&gt;
&lt;p&gt;Rocky Linux fits scenarios such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;enterprise environments that previously ran CentOS 7 / CentOS 8;&lt;/li&gt;
&lt;li&gt;RHEL-style directory structure, package names, and operations habits;&lt;/li&gt;
&lt;li&gt;reliance on &lt;code&gt;dnf&lt;/code&gt;, RPM, SELinux, and firewalld;&lt;/li&gt;
&lt;li&gt;software vendors that explicitly support RHEL-compatible distributions;&lt;/li&gt;
&lt;li&gt;internal automation scripts written around Enterprise Linux.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Its advantage is low migration friction. Many teams have years of CentOS-based Ansible playbooks, monitoring rules, audit scripts, and security baselines. Moving to Rocky Linux is mentally much easier than moving to Debian or Ubuntu.&lt;/p&gt;
&lt;p&gt;Things to note about Rocky Linux:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;packages are conservative by design; this is a feature of Enterprise Linux, not a flaw;&lt;/li&gt;
&lt;li&gt;very new user-space components may require EPEL, third-party repositories, or containers;&lt;/li&gt;
&lt;li&gt;RHEL compatibility does not mean every commercial software vendor automatically offers formal support, so check certification lists;&lt;/li&gt;
&lt;li&gt;Rocky Linux 10 has new hardware baselines and ecosystem requirements, so validate before production.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My take: if your server environment is already CentOS / RHEL based, Rocky Linux is a very natural replacement, especially for stable production environments and internal enterprise services.&lt;/p&gt;
&lt;h2 id=&#34;almalinux-a-more-proactive-rhel-compatible-route&#34;&gt;AlmaLinux: A More Proactive RHEL-Compatible Route
&lt;/h2&gt;&lt;p&gt;AlmaLinux is another important CentOS successor. It is also enterprise-grade, long-term supported, and RHEL compatible.&lt;/p&gt;
&lt;p&gt;It shares many traits with Rocky Linux:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;both target the RHEL-compatible ecosystem;&lt;/li&gt;
&lt;li&gt;both fit server production environments;&lt;/li&gt;
&lt;li&gt;both have long-term 8, 9, and 10 release lines;&lt;/li&gt;
&lt;li&gt;both are suitable for CentOS migration;&lt;/li&gt;
&lt;li&gt;both can use a large set of Enterprise Linux ecosystem tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The difference is that AlmaLinux is more proactive in documenting and handling upstream differences while remaining RHEL compatible. For example, AlmaLinux 10 provides an &lt;code&gt;x86-64-v2&lt;/code&gt; architecture option for older hardware and clearly documents differences from RHEL in release notes.&lt;/p&gt;
&lt;p&gt;This is useful for some users: they want to stay in the RHEL ecosystem but also want a community distribution with more flexibility around hardware support, package builds, and EPEL compatibility.&lt;/p&gt;
&lt;p&gt;AlmaLinux is suitable when:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;you need RHEL compatibility but do not want to be fully constrained by RHEL release strategy;&lt;/li&gt;
&lt;li&gt;you value community governance and transparent release notes;&lt;/li&gt;
&lt;li&gt;you need a stable base system for cloud platforms, container images, and enterprise workloads;&lt;/li&gt;
&lt;li&gt;you want a smooth migration from CentOS or older Enterprise Linux.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key caution: AlmaLinux is not &amp;ldquo;identical to RHEL with your eyes closed.&amp;rdquo; For strict compliance, vendor certification, database certification, or hardware certification scenarios, check whether the software vendor explicitly supports AlmaLinux.&lt;/p&gt;
&lt;p&gt;My take: both Rocky Linux and AlmaLinux can replace CentOS. If you prefer a more conservative and traditional CentOS-style story, look at Rocky. If you value community transparency and a more flexible compatibility route, look at AlmaLinux.&lt;/p&gt;
&lt;h2 id=&#34;ubuntu-server-best-cloud-support-and-deployment-efficiency&#34;&gt;Ubuntu Server: Best Cloud Support and Deployment Efficiency
&lt;/h2&gt;&lt;p&gt;Ubuntu Server&amp;rsquo;s advantage is practical: cloud platforms, documentation, community tutorials, images, automation tools, and developer ecosystem are all strong.&lt;/p&gt;
&lt;p&gt;For new server deployments in 2026, the main choice is still Ubuntu 24.04 LTS. Ubuntu LTS usually has 5 years of standard support and can be extended through ESM. For cloud servers, container hosts, development environments, and CI/CD nodes, Ubuntu Server is often the fastest to get working.&lt;/p&gt;
&lt;p&gt;Ubuntu Server fits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS, Azure, Google Cloud, Oracle Cloud, Alibaba Cloud, Tencent Cloud, and other cloud servers;&lt;/li&gt;
&lt;li&gt;Docker, Kubernetes, GitLab Runner, CI/CD;&lt;/li&gt;
&lt;li&gt;AI / GPU / CUDA development environments;&lt;/li&gt;
&lt;li&gt;teams that need abundant tutorials and community recipes;&lt;/li&gt;
&lt;li&gt;environments where development and production should stay similar.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ubuntu&amp;rsquo;s strengths:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;high-quality cloud images;&lt;/li&gt;
&lt;li&gt;lots of official and third-party documentation;&lt;/li&gt;
&lt;li&gt;often more active new hardware support;&lt;/li&gt;
&lt;li&gt;clear LTS cadence;&lt;/li&gt;
&lt;li&gt;convenient developer toolchain updates;&lt;/li&gt;
&lt;li&gt;many commercial software vendors provide Ubuntu installation instructions first.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Things to watch:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;not every team likes Snap on servers, so decide your policy in advance;&lt;/li&gt;
&lt;li&gt;PPAs are convenient, but overusing them in production increases maintenance risk;&lt;/li&gt;
&lt;li&gt;choose clearly between HWE kernel, cloud kernel, and standard kernel;&lt;/li&gt;
&lt;li&gt;for minimal-stability purists, Ubuntu&amp;rsquo;s default system feels busier than Debian.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My take: if you mainly run cloud servers, containers, development deployment, or AI toolchains, Ubuntu Server is usually the most efficient choice. It is not the most &amp;ldquo;pure&amp;rdquo; distribution, but it reduces lookup time and friction for many tasks.&lt;/p&gt;
&lt;h2 id=&#34;how-to-choose-among-the-four&#34;&gt;How to Choose Among the Four
&lt;/h2&gt;&lt;h3 id=&#34;personal-vps--self-hosting&#34;&gt;Personal VPS / Self-Hosting
&lt;/h3&gt;&lt;p&gt;Debian or Ubuntu Server first.&lt;/p&gt;
&lt;p&gt;If you want stability, low maintenance, and less fuss, choose Debian. If you often follow tutorials to deploy new projects or need a newer software stack, choose Ubuntu Server.&lt;/p&gt;
&lt;h3 id=&#34;enterprise-production&#34;&gt;Enterprise Production
&lt;/h3&gt;&lt;p&gt;Rocky Linux, AlmaLinux, or RHEL first.&lt;/p&gt;
&lt;p&gt;If the company used CentOS before, migration to Rocky / Alma is the cheapest path. If commercial databases, hardware certification, security compliance, or vendor support are involved, check certification lists first.&lt;/p&gt;
&lt;h3 id=&#34;cloud-native-and-container-hosts&#34;&gt;Cloud Native and Container Hosts
&lt;/h3&gt;&lt;p&gt;Ubuntu Server, Debian, and Rocky / Alma can all work.&lt;/p&gt;
&lt;p&gt;If the team values development efficiency, choose Ubuntu Server. If you want minimal stability, choose Debian. If the enterprise standard is RHEL-based, choose Rocky / Alma.&lt;/p&gt;
&lt;h3 id=&#34;ai--gpu-servers&#34;&gt;AI / GPU Servers
&lt;/h3&gt;&lt;p&gt;Look at Ubuntu Server first, then Rocky / Alma.&lt;/p&gt;
&lt;p&gt;The reason is simple: NVIDIA, CUDA, PyTorch, TensorFlow, driver installation tutorials, and community experience are usually richest on Ubuntu. Enterprise GPU clusters built around the RHEL ecosystem can choose Rocky / Alma, but drivers, CUDA, container runtime, and monitoring tools should be validated in advance.&lt;/p&gt;
&lt;h3 id=&#34;traditional-business-systems&#34;&gt;Traditional Business Systems
&lt;/h3&gt;&lt;p&gt;Rocky Linux / AlmaLinux first.&lt;/p&gt;
&lt;p&gt;Traditional Java, databases, middleware, commercial software, auditing, and operations standards often lean toward the RHEL ecosystem. In that case, Rocky / Alma fits existing systems more easily than Debian / Ubuntu.&lt;/p&gt;
&lt;h2 id=&#34;what-to-check-before-choosing&#34;&gt;What to Check Before Choosing
&lt;/h2&gt;&lt;p&gt;Do not choose only by distribution name. For server selection, judge by these questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Lifecycle&lt;/strong&gt;: until which year is this version maintained?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upgrade path&lt;/strong&gt;: is major-version upgrade mature? Is smooth migration supported?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Software sources&lt;/strong&gt;: do you rely on third-party repositories? Who maintains them?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security updates&lt;/strong&gt;: are security advisories, patch cadence, and CVE handling clear?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hardware support&lt;/strong&gt;: have CPU, NIC, RAID, GPU, and storage controllers been validated?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Team experience&lt;/strong&gt;: is the team more familiar with &lt;code&gt;apt&lt;/code&gt; or &lt;code&gt;dnf&lt;/code&gt;? Debian-style or RHEL-style systems?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vendor certification&lt;/strong&gt;: does the business software explicitly support this distribution?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automation assets&lt;/strong&gt;: can existing Ansible, Terraform, and image-building scripts be reused?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The real cost is often not the installation ISO. It is upgrades, audits, troubleshooting, and handover over the next five years.&lt;/p&gt;
&lt;h2 id=&#34;my-default-recommendations&#34;&gt;My Default Recommendations
&lt;/h2&gt;&lt;p&gt;If I had to give a default 2026 server selection guide:&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Scenario&lt;/th&gt;
          &lt;th&gt;Recommendation&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Personal VPS, self-hosting&lt;/td&gt;
          &lt;td&gt;Debian 13&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Cloud server, fast deployment&lt;/td&gt;
          &lt;td&gt;Ubuntu Server 24.04 LTS&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;CentOS migration&lt;/td&gt;
          &lt;td&gt;Rocky Linux 9 / AlmaLinux 9&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;New enterprise project&lt;/td&gt;
          &lt;td&gt;Rocky Linux 10 / AlmaLinux 10, after ecosystem validation&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;AI / GPU development&lt;/td&gt;
          &lt;td&gt;Ubuntu Server 24.04 LTS&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Strict-compliance commercial production&lt;/td&gt;
          &lt;td&gt;RHEL, or Rocky / Alma after vendor support is confirmed&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;short-conclusion&#34;&gt;Short Conclusion
&lt;/h2&gt;&lt;p&gt;Debian&amp;rsquo;s keywords are stability, simplicity, community, and free-software tradition. It is suitable for long-running base servers.&lt;/p&gt;
&lt;p&gt;Rocky Linux and AlmaLinux are about RHEL compatibility, enterprise production, and CentOS replacement. They fit teams that already have Enterprise Linux operations systems.&lt;/p&gt;
&lt;p&gt;Ubuntu Server is about cloud, documentation, development efficiency, and ecosystem completeness. It fits fast deployment, containers, AI/GPU, and cloud servers.&lt;/p&gt;
&lt;p&gt;There is no forever-correct distribution. There is only the distribution that best matches your team, business, hardware, and lifecycle. The best server choice is usually not the hottest one, but the one you will still be willing to maintain five years later.&lt;/p&gt;
&lt;h2 id=&#34;related-links&#34;&gt;Related Links
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Debian Releases: &lt;a class=&#34;link&#34; href=&#34;https://www.debian.org/releases/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.debian.org/releases/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ubuntu Releases: &lt;a class=&#34;link&#34; href=&#34;https://releases.ubuntu.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://releases.ubuntu.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rocky Linux Release and Version Guide: &lt;a class=&#34;link&#34; href=&#34;https://wiki.rockylinux.org/rocky/version/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://wiki.rockylinux.org/rocky/version/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;AlmaLinux Release Notes: &lt;a class=&#34;link&#34; href=&#34;https://wiki.almalinux.org/release-notes/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://wiki.almalinux.org/release-notes/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Nginx Rate Limiting: Add rate limit for high-frequency 404 and 400 scan requests</title>
        <link>https://knightli.com/en/2026/05/01/nginx-rate-limit-404-400-scan-requests/</link>
        <pubDate>Fri, 01 May 2026 05:41:31 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/05/01/nginx-rate-limit-404-400-scan-requests/</guid>
        <description>&lt;p&gt;If your website logs suddenly show a large number of &lt;code&gt;404&lt;/code&gt; and &lt;code&gt;400&lt;/code&gt; responses, the cause is often not normal users clicking broken links. It is usually an automated scanner probing paths such as &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;wp-admin&lt;/code&gt;, &lt;code&gt;phpmyadmin&lt;/code&gt;, and &lt;code&gt;xmlrpc.php&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These requests create several problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;access log grows quickly&lt;/li&gt;
&lt;li&gt;error log fills with useless noise&lt;/li&gt;
&lt;li&gt;static sites or reverse proxy services waste connections on invalid requests&lt;/li&gt;
&lt;li&gt;real issues get buried under scan noise&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nginx can use &lt;code&gt;limit_req&lt;/code&gt; and &lt;code&gt;limit_conn&lt;/code&gt; to control this. But first, one point matters: Nginx cannot natively rate-limit directly by &amp;ldquo;response status code is 404 or 400&amp;rdquo;, because rate limiting happens before the response is generated.&lt;/p&gt;
&lt;p&gt;The practical approach is to rate-limit scan paths, suspicious sources, and high-frequency site-wide requests before they produce &lt;code&gt;404&lt;/code&gt; / &lt;code&gt;400&lt;/code&gt; responses.&lt;/p&gt;
&lt;h2 id=&#34;basic-idea&#34;&gt;Basic idea
&lt;/h2&gt;&lt;p&gt;Use three layers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Apply gentle site-wide rate limiting to prevent one IP from hammering the site.&lt;/li&gt;
&lt;li&gt;Apply strict rate limiting to common scan paths and return &lt;code&gt;404&lt;/code&gt; directly.&lt;/li&gt;
&lt;li&gt;Limit concurrent connections per IP.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A safer rollout order is: first add the scan path rule and &lt;code&gt;access_log off&lt;/code&gt;, observe for one day, and only add site-wide &lt;code&gt;limit_req&lt;/code&gt; if there are still many random-path &lt;code&gt;404&lt;/code&gt; requests.&lt;/p&gt;
&lt;h2 id=&#34;define-rate-limit-zones-in-http-first&#34;&gt;Define rate-limit zones in http first
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;limit_req_zone&lt;/code&gt; and &lt;code&gt;limit_conn_zone&lt;/code&gt; must be placed inside &lt;code&gt;http {}&lt;/code&gt;. They cannot be placed inside a single site&amp;rsquo;s &lt;code&gt;server {}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can add them directly to the &lt;code&gt;http {}&lt;/code&gt; block in &lt;code&gt;/etc/nginx/nginx.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;http&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 按客户端 IP 限速，普通页面请求
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_general:20m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=5r/s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 更严格：疑似扫描路径
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_scan:20m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=1r/s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 并发连接限制
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_conn_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=addr_conn:20m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/etc/nginx/conf.d/*.conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/etc/nginx/sites-enabled/*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;You can also create a new file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo nano /etc/nginx/conf.d/limit-zones.conf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Write:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_general:20m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=5r/s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_scan:20m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=1r/s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_conn_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=addr_conn:20m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This assumes your &lt;code&gt;nginx.conf&lt;/code&gt; really includes this inside &lt;code&gt;http {}&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;/etc/nginx/conf.d/*.conf&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;then-use-the-zones-in-server&#34;&gt;Then use the zones in server
&lt;/h2&gt;&lt;p&gt;A site config file is usually something like &lt;code&gt;/etc/nginx/sites-enabled/www.example.com&lt;/code&gt;, and it usually contains &lt;code&gt;server {}&lt;/code&gt;. Do not write &lt;code&gt;limit_req_zone&lt;/code&gt; there. Only use zones already defined earlier.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;19
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/srv/www/example.com&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;index.html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;server_name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;example.com&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;www.example.com&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;access_log&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/var/log/nginx/example.com.access.log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;error_log&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/var/log/nginx/example.com.error.log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 全站温和限速：允许短时突发，降低误伤正常用户的概率
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_req&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_general&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;burst=30&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;nodelay&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_conn&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;addr_conn&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 对常见扫描路径严格限速，并关闭访问日志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;~&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;^/(\.env|\.git|\.svn|wp-|wp/|adminer|phpmyadmin|pma|vendor|backup|config|server-status|cgi-bin|xmlrpc\.php)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;access_log&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;off&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;limit_req&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_scan&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;burst=5&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;nodelay&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kn&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;404&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 你原来的 location /、listen ssl 等配置继续放这里
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If you are worried about hurting normal traffic with site-wide rate limiting, start with only the scan path rule:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;~&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;^/(\.env|\.git|\.svn|wp-|wp/|adminer|phpmyadmin|pma|vendor|backup|config|server-status|cgi-bin|xmlrpc\.php)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;access_log&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;off&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_req&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_scan&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;burst=5&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;nodelay&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;404&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;what-these-parameters-mean&#34;&gt;What these parameters mean
&lt;/h2&gt;&lt;p&gt;This line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_general:20m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=5r/s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;limit_req_zone&lt;/code&gt;: defines the accounting zone for request rate limiting.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$binary_remote_addr&lt;/code&gt;: uses client IP as the rate-limit key, and uses less memory than &lt;code&gt;$remote_addr&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zone=perip_general:20m&lt;/code&gt;: creates a shared memory zone named &lt;code&gt;perip_general&lt;/code&gt; with size &lt;code&gt;20m&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rate=5r/s&lt;/code&gt;: each IP is allowed an average of 5 requests per second.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_scan:20m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=1r/s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;is similar, but stricter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;perip_scan&lt;/code&gt;: used specifically for suspicious scan paths.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rate=1r/s&lt;/code&gt;: each IP is allowed only 1 request per second.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_conn_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=addr_conn:20m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;limit_conn_zone&lt;/code&gt;: defines the accounting zone for concurrent connection limits.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$binary_remote_addr&lt;/code&gt;: still counts by client IP.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zone=addr_conn:20m&lt;/code&gt;: creates a connection-counting shared memory zone named &lt;code&gt;addr_conn&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The actual concurrent connection limit is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_conn&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;addr_conn&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;It means each IP can have at most 20 simultaneous connections.&lt;/p&gt;
&lt;h2 id=&#34;understanding-burst-and-nodelay&#34;&gt;Understanding burst and nodelay
&lt;/h2&gt;&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;limit_req&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_general&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;burst=30&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;nodelay&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;You can read it like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rate=5r/s&lt;/code&gt;: the long-term average rate is 5 requests per second.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;burst=30&lt;/code&gt;: allow 30 extra requests during a short burst.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nodelay&lt;/code&gt;: when requests exceed the average rate but are still within &lt;code&gt;burst&lt;/code&gt;, process them immediately instead of queueing; reject only after &lt;code&gt;burst&lt;/code&gt; is exceeded.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without &lt;code&gt;nodelay&lt;/code&gt;, Nginx tries to delay and queue some requests. For ordinary web pages, &lt;code&gt;nodelay&lt;/code&gt; is usually easier to reason about. For APIs or especially sensitive endpoints, adjust according to actual behavior.&lt;/p&gt;
&lt;h2 id=&#34;common-error-limit_req_zone-in-the-wrong-place&#34;&gt;Common error: limit_req_zone in the wrong place
&lt;/h2&gt;&lt;p&gt;If you see this error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2026/04/30 21:33:48 [emerg] 2290771#2290771: &amp;#34;limit_req_zone&amp;#34; directive is not allowed here in /etc/nginx/sites-enabled/example.com:9
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;It means &lt;code&gt;limit_req_zone&lt;/code&gt; was written in a context where it is not allowed.&lt;/p&gt;
&lt;p&gt;A common incorrect configuration is placing it inside &lt;code&gt;server {}&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/srv/www/example.com&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;index.html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;server_name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;example.com&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;www.example.com&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_general:20m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=5r/s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_req_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=perip_scan:20m&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;rate=1r/s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kn&#34;&gt;limit_conn_zone&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$binary_remote_addr&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;zone=addr_conn:20m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This will not work.&lt;/p&gt;
&lt;p&gt;One-line memory aid:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;limit_req_zone&lt;/code&gt; defines the pool, so put it in &lt;code&gt;http {}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;limit_req&lt;/code&gt; uses the pool, so put it in &lt;code&gt;server {}&lt;/code&gt; or &lt;code&gt;location {}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;limit_conn_zone&lt;/code&gt; defines the connection pool, so put it in &lt;code&gt;http {}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;limit_conn&lt;/code&gt; uses the connection pool, so put it in &lt;code&gt;server {}&lt;/code&gt; or &lt;code&gt;location {}&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;temporarily-block-clearly-abnormal-ips&#34;&gt;Temporarily block clearly abnormal IPs
&lt;/h2&gt;&lt;p&gt;If the logs confirm that several IPs are continuously sending scan requests, you can temporarily block them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;deny&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;45.95.42.164&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;deny&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;185.177.72.51&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;deny&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;185.177.72.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;deny&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;185.177.72.56&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;deny&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;185.177.72.58&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;These &lt;code&gt;deny&lt;/code&gt; directives can be placed inside &lt;code&gt;server {}&lt;/code&gt; or a specific &lt;code&gt;location {}&lt;/code&gt;. Whether to keep them long term depends on false-positive risk and traffic sources.&lt;/p&gt;
&lt;h2 id=&#34;check-and-reload&#34;&gt;Check and reload
&lt;/h2&gt;&lt;p&gt;Check the configuration first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo nginx -t
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If there is no error, reload:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo systemctl reload nginx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Do not restart the service directly. &lt;code&gt;reload&lt;/code&gt; lets Nginx load the new configuration gracefully, which is safer.&lt;/p&gt;
&lt;h2 id=&#34;recommended-parameters&#34;&gt;Recommended parameters
&lt;/h2&gt;&lt;p&gt;For a personal site or static site, start with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;normal pages: &lt;code&gt;rate=5r/s&lt;/code&gt; to &lt;code&gt;10r/s&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;scan paths: &lt;code&gt;rate=1r/s&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;scan path &lt;code&gt;burst=5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;site-wide &lt;code&gt;burst=30&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;per-IP concurrency: &lt;code&gt;10&lt;/code&gt; to &lt;code&gt;20&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If normal traffic is very low, the settings can be stricter. If the site has many images, scripts, or API requests, loosen the normal page limit to avoid hurting real users.&lt;/p&gt;
&lt;p&gt;The safest approach is a staged rollout:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First apply &lt;code&gt;access_log off&lt;/code&gt; + &lt;code&gt;return 404&lt;/code&gt; to scan paths.&lt;/li&gt;
&lt;li&gt;Then add strict &lt;code&gt;perip_scan&lt;/code&gt; rate limiting.&lt;/li&gt;
&lt;li&gt;Observe logs for one day.&lt;/li&gt;
&lt;li&gt;If random-path 404s are still heavy, enable gentle site-wide rate limiting.&lt;/li&gt;
&lt;/ol&gt;
</description>
        </item>
        <item>
        <title>Ubuntu 26.04 LTS GPU and Hardware Updates: CUDA, ROCm, DPC&#43;&#43;, and More Platform Changes</title>
        <link>https://knightli.com/en/2026/04/26/ubuntu-26-04-lts-gpu-hardware-ai-updates/</link>
        <pubDate>Sun, 26 Apr 2026 19:35:57 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/04/26/ubuntu-26-04-lts-gpu-hardware-ai-updates/</guid>
        <description>&lt;p&gt;If the previous article worked as a desktop-focused overview of &lt;code&gt;Ubuntu 26.04 LTS&lt;/code&gt;, this one is better read as its hardware and compute-side follow-up. In this &lt;code&gt;26.04&lt;/code&gt; cycle, Ubuntu pushed a number of AI, GPU computing, and platform compatibility changes into the main archive or formal support scope.&lt;/p&gt;
&lt;p&gt;The short version is this: the most important part of this round is not just desktop and kernel upgrades, but that &lt;strong&gt;Ubuntu is bringing Intel, NVIDIA, and AMD GPU computing stacks into the distribution in a more systematic way&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;1-intel-dpc-and-related-components-are-now-in-ubuntu-archive&#34;&gt;1. Intel DPC++ and related components are now in Ubuntu Archive
&lt;/h2&gt;&lt;p&gt;Starting with &lt;code&gt;26.04&lt;/code&gt;, Intel&amp;rsquo;s open-source &lt;code&gt;oneAPI DPC++&lt;/code&gt; compiler is available directly from Ubuntu Archive for building &lt;code&gt;SYCL&lt;/code&gt; code. Its runtime also includes adapters for Intel GPUs.&lt;/p&gt;
&lt;p&gt;Two related components are also now available from Ubuntu repositories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;oneDPL&lt;/code&gt;, the DPC++ library, which provides higher-productivity developer APIs&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oneDNN&lt;/code&gt;, built with &lt;code&gt;dpclang-6&lt;/code&gt;, which can run on Intel GPUs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That means if you are already working with &lt;code&gt;SYCL&lt;/code&gt;, heterogeneous computing, or AI workloads on Intel GPUs, Ubuntu now offers a more direct path instead of forcing you to maintain a separate external stack for everything.&lt;/p&gt;
&lt;p&gt;Ubuntu also calls out one practical requirement: users need to be in the &lt;code&gt;render&lt;/code&gt; group to actually use these Intel GPU-related capabilities.&lt;/p&gt;
&lt;h2 id=&#34;2-the-nvidia-cuda-toolkit-can-now-be-installed-directly-with-apt&#34;&gt;2. The NVIDIA CUDA toolkit can now be installed directly with &lt;code&gt;apt&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;For many developers and operators, this may be one of the most immediately useful changes in the notes.&lt;/p&gt;
&lt;p&gt;Starting with &lt;code&gt;26.04&lt;/code&gt;, the &lt;code&gt;NVIDIA CUDA toolkit&lt;/code&gt; can now be installed directly from Ubuntu Archive:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install cuda-toolkit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The value here is bigger than just saving a few setup steps.&lt;/p&gt;
&lt;p&gt;For developers shipping software on Ubuntu, this new model means they can simply declare a dependency on the &lt;code&gt;CUDA runtime&lt;/code&gt;, while Ubuntu manages installation and compatibility at the distribution level. That makes CUDA feel more like a native system capability on Ubuntu, rather than an extra software layer that always has to be maintained separately.&lt;/p&gt;
&lt;h2 id=&#34;3-amd-rocm-710-is-now-in-universe&#34;&gt;3. AMD ROCm 7.1.0 is now in Universe
&lt;/h2&gt;&lt;p&gt;On the AMD side, Ubuntu Universe now includes &lt;code&gt;ROCm 7.1.0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These libraries mainly provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;backend infrastructure for AI training and inference on AMD GPUs&lt;/li&gt;
&lt;li&gt;software foundations for machine learning and high performance computing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Canonical also notes that ROCm-related components are continuously tested in its CI/CD pipeline. Beyond &lt;code&gt;autopkgtests&lt;/code&gt;, that includes several user-space applications such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;llama.cpp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pytorch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Blender&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Lemonade Server&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That detail matters, because it shows Ubuntu is not just dropping packages into the archive. It is validating ROCm as a maintainable software stack.&lt;/p&gt;
&lt;h2 id=&#34;4-the-bigger-story-is-that-all-three-gpu-ecosystems-are-landing&#34;&gt;4. The bigger story is that all three GPU ecosystems are landing
&lt;/h2&gt;&lt;p&gt;It becomes easier to see the direction of &lt;code&gt;26.04&lt;/code&gt; when &lt;code&gt;DPC++&lt;/code&gt;, &lt;code&gt;CUDA&lt;/code&gt;, and &lt;code&gt;ROCm&lt;/code&gt; are viewed together:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Intel: bringing &lt;code&gt;SYCL&lt;/code&gt; / &lt;code&gt;oneAPI&lt;/code&gt; components into official repositories&lt;/li&gt;
&lt;li&gt;NVIDIA: giving the &lt;code&gt;CUDA toolkit&lt;/code&gt; a distribution-managed installation path&lt;/li&gt;
&lt;li&gt;AMD: shipping &lt;code&gt;ROCm 7.1.0&lt;/code&gt; in Universe with ongoing testing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you work with these kinds of workloads on Ubuntu, this release will probably feel more relevant:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;local LLM inference&lt;/li&gt;
&lt;li&gt;GPU-accelerated training or fine-tuning&lt;/li&gt;
&lt;li&gt;Blender, scientific computing, and HPC&lt;/li&gt;
&lt;li&gt;development environments that need to move across different GPU platforms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, Ubuntu is no longer just &amp;ldquo;a system where you can install a GPU driver.&amp;rdquo; It is starting to carry a fuller &lt;strong&gt;user-space software stack for AI and GPU computing&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;5-nvidia-dynamic-boost-is-enabled-by-default&#34;&gt;5. NVIDIA Dynamic Boost is enabled by default
&lt;/h2&gt;&lt;p&gt;Since &lt;code&gt;25.04&lt;/code&gt;, &lt;code&gt;Dynamic Boost&lt;/code&gt; has been enabled by default on supported NVIDIA laptops.&lt;/p&gt;
&lt;p&gt;The idea is straightforward: depending on system load, power can be shifted dynamically between the CPU and GPU. In gaming scenarios, that usually means giving more power to the GPU when needed to extract more performance.&lt;/p&gt;
&lt;p&gt;It only applies under two conditions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the laptop is connected to AC power&lt;/li&gt;
&lt;li&gt;the GPU load is high enough&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It does not engage while the system is running on battery.&lt;/p&gt;
&lt;h2 id=&#34;6-support-for-new-intel-integrated-and-discrete-gpus-keeps-moving-forward&#34;&gt;6. Support for new Intel integrated and discrete GPUs keeps moving forward
&lt;/h2&gt;&lt;p&gt;Ubuntu also continues expanding support for new Intel GPUs, including:&lt;/p&gt;
&lt;p&gt;Integrated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Intel Core Ultra Xe2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Intel Core Ultra Xe3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Discrete:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Intel Arc 5 B570&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Intel Arc 5 B580&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Intel Arc Pro B50&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Intel Arc Pro B60&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Intel Arc Pro B65&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Intel Arc Pro B70&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ubuntu also highlights several features already available around these devices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;improved GPU and CPU ray tracing performance through Intel Embree, benefiting applications such as &lt;code&gt;Blender 4.2+&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;hardware video encoding for &lt;code&gt;AVC&lt;/code&gt;, &lt;code&gt;JPEG&lt;/code&gt;, &lt;code&gt;HEVC&lt;/code&gt;, and &lt;code&gt;AV1&lt;/code&gt; on &amp;ldquo;Battlemage&amp;rdquo; devices&lt;/li&gt;
&lt;li&gt;a new &lt;code&gt;CCS&lt;/code&gt; optimization in Intel Compute Runtime&lt;/li&gt;
&lt;li&gt;enabled debugging support for Intel Xe GPUs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are watching follow-up releases, &lt;code&gt;25.10&lt;/code&gt; also continues to bring in more capabilities, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;initial support for Intel&amp;rsquo;s next-generation client platform codenamed &lt;code&gt;Panther Lake&lt;/code&gt; through &lt;code&gt;Linux kernel 6.17&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;improved IOMMU, PCIe subsystem, and multi-GPU support&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Mesa 25.2.3&lt;/code&gt; enabling &lt;code&gt;VK_KHR_shader_bfloat16&lt;/code&gt; for Battlemage and Panther Lake&lt;/li&gt;
&lt;li&gt;&lt;code&gt;intel-media-driver 25.3.0&lt;/code&gt; adding Panther Lake decode support and &lt;code&gt;VP9&lt;/code&gt; encoding&lt;/li&gt;
&lt;li&gt;&lt;code&gt;intel-compute-runtime 25.31&lt;/code&gt; adjusting the Level Zero &lt;code&gt;USM&lt;/code&gt; pool and local device memory event allocation behavior&lt;/li&gt;
&lt;li&gt;&lt;code&gt;level-zero 1.24&lt;/code&gt; and &lt;code&gt;level-zero-raytracing 1.1.0&lt;/code&gt; bringing broader spec and RTAS extension support&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;7-suspend-and-resume-is-more-stable-on-nvidia-desktops-too&#34;&gt;7. Suspend and resume is more stable on Nvidia desktops too
&lt;/h2&gt;&lt;p&gt;Starting with &lt;code&gt;25.10&lt;/code&gt;, Ubuntu enables suspend-resume support in the proprietary &lt;code&gt;Nvidia&lt;/code&gt; driver to reduce corruption and freezing when waking a desktop system.&lt;/p&gt;
&lt;p&gt;This is not the most visible kind of change, but it matters a lot in everyday use, especially on desktops that stay on for long periods and frequently suspend and resume.&lt;/p&gt;
&lt;h2 id=&#34;8-arm-raspberry-pi-risc-v-and-ibm-z-also-get-harder-platform-level-changes&#34;&gt;8. ARM, Raspberry Pi, RISC-V, and IBM Z also get harder platform-level changes
&lt;/h2&gt;&lt;p&gt;Beyond the GPU software stack, the release notes also include several platform-level changes worth calling out separately.&lt;/p&gt;
&lt;h3 id=&#34;arm64-desktop-platforms&#34;&gt;ARM64 desktop platforms
&lt;/h3&gt;&lt;p&gt;Starting with &lt;code&gt;25.10&lt;/code&gt;, the &lt;code&gt;ARM64&lt;/code&gt; &lt;code&gt;linux-generic&lt;/code&gt; kernel provides broader desktop compatibility for ARM64 desktop platforms that boot through &lt;code&gt;UEFI&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;a-new-raspberry-pi-boot-layout&#34;&gt;A new Raspberry Pi boot layout
&lt;/h3&gt;&lt;p&gt;One change introduced in &lt;code&gt;25.10&lt;/code&gt; and refined in &lt;code&gt;26.04&lt;/code&gt; is a new boot partition layout for Raspberry Pi systems.&lt;/p&gt;
&lt;p&gt;Its goal is to improve boot reliability: newly written boot assets are first &amp;ldquo;tested&amp;rdquo; before they are committed as the new &amp;ldquo;known good&amp;rdquo; set.&lt;/p&gt;
&lt;p&gt;The firmware date requirements are the part most users will want to remember:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Pi 3 / 3+ / CM3+ / Zero 2W&lt;/code&gt;: no additional action required, the boot firmware is in the image itself&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Pi 4 / 400 / CM4&lt;/code&gt;: boot firmware must be dated no earlier than &lt;code&gt;2022-11-25&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Pi 5 / 500 / CM5&lt;/code&gt;: boot firmware must be dated no earlier than &lt;code&gt;2025-02-11&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can check it with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo rpi-eeprom-update
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If the firmware is too old and you are using &lt;code&gt;Ubuntu 24.04 LTS&lt;/code&gt; or newer, you can update it like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo rpi-eeprom-update -a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id=&#34;raspberry-pi-desktop-images-now-use-desktop-minimal&#34;&gt;Raspberry Pi desktop images now use desktop-minimal
&lt;/h3&gt;&lt;p&gt;Since &lt;code&gt;25.10&lt;/code&gt;, Ubuntu Desktop images for Raspberry Pi are based on &lt;code&gt;desktop-minimal&lt;/code&gt; rather than the full &lt;code&gt;desktop&lt;/code&gt; seed.&lt;/p&gt;
&lt;p&gt;Ubuntu gives a very concrete benefit here: the default app set is smaller, saving about &lt;code&gt;777MB&lt;/code&gt; on the uncompressed image and on installed systems.&lt;/p&gt;
&lt;p&gt;If you want to remove that default app set in bulk after upgrading, you can use:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt purge ubuntu-desktop --autoremove
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If you want to keep some of those applications, just mark them as manually installed with &lt;code&gt;apt&lt;/code&gt; first.&lt;/p&gt;
&lt;h3 id=&#34;swap-on-raspberry-pi-is-now-handled-by-cloud-init&#34;&gt;Swap on Raspberry Pi is now handled by cloud-init
&lt;/h3&gt;&lt;p&gt;Since &lt;code&gt;25.10&lt;/code&gt;, swap file creation on Raspberry Pi desktop images is handled by &lt;code&gt;cloud-init&lt;/code&gt;.&lt;br&gt;
If you want to customize swap size before first boot, you can edit &lt;code&gt;user-data&lt;/code&gt; on the boot partition directly.&lt;/p&gt;
&lt;h3 id=&#34;risc-v-requirements-have-moved-up&#34;&gt;RISC-V requirements have moved up
&lt;/h3&gt;&lt;p&gt;Starting with &lt;code&gt;25.10&lt;/code&gt;, the &lt;code&gt;RISC-V&lt;/code&gt; build of &lt;code&gt;Ubuntu 26.04 LTS&lt;/code&gt; requires hardware that implements the &lt;code&gt;RVA23S64 ISA profile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Systems that do not meet that requirement can no longer run &lt;code&gt;Ubuntu 26.04 LTS&lt;/code&gt;. If you still have boards based on earlier &lt;code&gt;RVA20&lt;/code&gt; processor cores, you need to stay on the support line provided by &lt;code&gt;Ubuntu 24.04 LTS&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;According to Ubuntu, as of &lt;code&gt;April 2026&lt;/code&gt;, there is still no real &lt;code&gt;RVA23S64&lt;/code&gt; hardware available. So the only currently supported platform is effectively a &lt;code&gt;QEMU&lt;/code&gt; virtualized environment configured with &lt;code&gt;-cpu rva23s64&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;ibm-z-now-requires-z15-at-minimum&#34;&gt;IBM Z now requires z15 at minimum
&lt;/h3&gt;&lt;p&gt;Starting with &lt;code&gt;26.04&lt;/code&gt;, the minimum requirement for the &lt;code&gt;s390x&lt;/code&gt; architecture has moved up to &lt;code&gt;z15&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;z14&lt;/code&gt; / &lt;code&gt;LinuxONE II&lt;/code&gt; and older systems can no longer install &lt;code&gt;Ubuntu 26.04 LTS&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;z15&lt;/code&gt; / &lt;code&gt;LinuxONE III&lt;/code&gt; and newer systems should see better performance&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;9-who-should-read-this-first&#34;&gt;9. Who should read this first
&lt;/h2&gt;&lt;p&gt;This article is more useful than the desktop overview if you fall into any of these cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you use Ubuntu for &lt;code&gt;CUDA&lt;/code&gt;, &lt;code&gt;ROCm&lt;/code&gt;, &lt;code&gt;SYCL&lt;/code&gt;, or local AI inference&lt;/li&gt;
&lt;li&gt;you do development or compute work on Intel, NVIDIA, or AMD GPUs&lt;/li&gt;
&lt;li&gt;you maintain Raspberry Pi, ARM64, RISC-V, IBM Z, or other non-standard x86 platforms&lt;/li&gt;
&lt;li&gt;you are especially sensitive to repository availability, driver behavior, runtimes, and platform requirements after an upgrade&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;10-one-line-takeaway&#34;&gt;10. One-line takeaway
&lt;/h2&gt;&lt;p&gt;The key point of &lt;code&gt;Ubuntu 26.04 LTS&lt;/code&gt; on the hardware and AI stack side is not that one GPU vendor got a standout upgrade. It is that &lt;strong&gt;Intel&amp;rsquo;s DPC++, NVIDIA&amp;rsquo;s CUDA, and AMD&amp;rsquo;s ROCm are all entering the Ubuntu ecosystem in a more official, in-repository, and maintainable way&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you used to think of Ubuntu as &amp;ldquo;the system first, then I assemble the GPU environment myself,&amp;rdquo; &lt;code&gt;26.04&lt;/code&gt; starts to look more like a distribution that is willing to actively carry AI and heterogeneous computing workloads.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Ubuntu 26.04 LTS Released: Major Desktop Updates with GNOME 50 and Linux 7.0</title>
        <link>https://knightli.com/en/2026/04/26/ubuntu-26-04-lts-release-notes/</link>
        <pubDate>Sun, 26 Apr 2026 16:10:25 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/04/26/ubuntu-26-04-lts-release-notes/</guid>
        <description>&lt;p&gt;&lt;code&gt;Ubuntu 26.04 LTS&lt;/code&gt; was released on &lt;strong&gt;April 23, 2026&lt;/strong&gt;, under the codename &lt;code&gt;Resolute Raccoon&lt;/code&gt;. This is the new long-term support release, with standard support through &lt;strong&gt;April 2031&lt;/strong&gt;. If you use &lt;code&gt;Ubuntu Pro&lt;/code&gt;, security maintenance can be extended to &lt;strong&gt;10 years&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you are upgrading from &lt;code&gt;Ubuntu 24.04 LTS&lt;/code&gt;, this is more than a routine release. It also folds in the major changes introduced across &lt;code&gt;24.10&lt;/code&gt;, &lt;code&gt;25.04&lt;/code&gt;, and &lt;code&gt;25.10&lt;/code&gt;. So this article works best as a quick guide to what is worth checking before you upgrade.&lt;/p&gt;
&lt;p&gt;If you only want the biggest takeaways from this release, remember these four points first:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GNOME 50&lt;/code&gt; has landed in an LTS release, bringing clearer improvements to desktop experience and display support&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Linux kernel 7.0&lt;/code&gt; becomes the new baseline, refreshing both hardware support and the long-term maintenance base&lt;/li&gt;
&lt;li&gt;Ubuntu Desktop has now fully moved to &lt;code&gt;Wayland&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The default app set has been refreshed across the board, with major updates to &lt;code&gt;Firefox&lt;/code&gt;, &lt;code&gt;LibreOffice&lt;/code&gt;, &lt;code&gt;Thunderbird&lt;/code&gt;, and &lt;code&gt;GIMP&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;1-start-with-the-key-updates&#34;&gt;1. Start with the key updates
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Ubuntu 26.04 LTS&lt;/code&gt; is a long-term support release with standard support through &lt;code&gt;2031-04&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The desktop environment has been updated to &lt;code&gt;GNOME 50&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The generic kernel has moved to &lt;code&gt;Linux kernel 7.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Ubuntu Desktop now provides only a &lt;code&gt;Wayland&lt;/code&gt; session&lt;/li&gt;
&lt;li&gt;Older versions cannot jump directly to &lt;code&gt;26.04&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are still on &lt;code&gt;Ubuntu 22.04 LTS&lt;/code&gt; or &lt;code&gt;25.04&lt;/code&gt;, the official recommendation is to upgrade to &lt;code&gt;Ubuntu 24.04 LTS&lt;/code&gt; or &lt;code&gt;25.10&lt;/code&gt; first, then continue to &lt;code&gt;26.04 LTS&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;2-biggest-change-1-gnome-50-is-now-in-lts&#34;&gt;2. Biggest change #1: GNOME 50 is now in LTS
&lt;/h2&gt;&lt;p&gt;The most visible desktop-side change this time is that &lt;code&gt;GNOME 50&lt;/code&gt; has finally entered an LTS release. For most users, the value is not one flashy standalone feature, but a smoother desktop experience overall:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better usability on small screens and narrow windows&lt;/li&gt;
&lt;li&gt;Notifications can be grouped by app&lt;/li&gt;
&lt;li&gt;Continued improvements to HDR, VRR, and fractional scaling&lt;/li&gt;
&lt;li&gt;Better smoothness and stability in remote desktop, Wayland, and NVIDIA-related scenarios&lt;/li&gt;
&lt;li&gt;Stronger accessibility support, including clear updates to the &lt;code&gt;Orca&lt;/code&gt; screen reader&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ubuntu has also added a few practical changes of its own:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GNOME Shell global search can directly find available &lt;code&gt;snap&lt;/code&gt; apps&lt;/li&gt;
&lt;li&gt;Web searches can also be triggered directly from search&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Yaru&lt;/code&gt; theme continues moving closer to upstream GNOME styling&lt;/li&gt;
&lt;li&gt;Permissions, file access, and drag-and-drop behavior for &lt;code&gt;snap&lt;/code&gt; apps feel more natural on the desktop&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you mainly use the desktop edition, the real point of this LTS is not a dramatic visual overhaul. It is that many small frictions from the past have been polished away together.&lt;/p&gt;
&lt;h2 id=&#34;3-biggest-change-2-the-default-apps-got-a-broad-refresh&#34;&gt;3. Biggest change #2: the default apps got a broad refresh
&lt;/h2&gt;&lt;p&gt;Compared with &lt;code&gt;24.04 LTS&lt;/code&gt;, the built-in app set in &lt;code&gt;26.04 LTS&lt;/code&gt; has been updated in a big way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Firefox&lt;/code&gt; moves to &lt;code&gt;150&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LibreOffice&lt;/code&gt; goes from &lt;code&gt;24.2&lt;/code&gt; to &lt;code&gt;25.8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Thunderbird&lt;/code&gt; moves to &lt;code&gt;140&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GIMP&lt;/code&gt; jumps from &lt;code&gt;2.10&lt;/code&gt; to &lt;code&gt;3.2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also several replacements that matter in day-to-day use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The PDF viewer is now &lt;code&gt;Papers&lt;/code&gt;, replacing &lt;code&gt;Evince&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The image viewer is now &lt;code&gt;Loupe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The terminal is now &lt;code&gt;Ptyxis&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The system monitor is now &lt;code&gt;Resources&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The default video player is now &lt;code&gt;Showtime&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The direction behind these changes is clear: Ubuntu is leaning more fully into a new generation of GNOME applications built on &lt;code&gt;GTK4&lt;/code&gt;, &lt;code&gt;libadwaita&lt;/code&gt;, and in some cases Rust-based rewrites.&lt;/p&gt;
&lt;h2 id=&#34;4-biggest-change-3-wayland-is-now-the-only-desktop-session&#34;&gt;4. Biggest change #3: Wayland is now the only desktop session
&lt;/h2&gt;&lt;p&gt;This is the most important change for many long-time users.&lt;/p&gt;
&lt;p&gt;The shift that started in &lt;code&gt;25.10&lt;/code&gt; is now fully settled in &lt;code&gt;26.04 LTS&lt;/code&gt;: Ubuntu Desktop runs only on the &lt;code&gt;Wayland&lt;/code&gt; backend, because &lt;code&gt;GNOME Shell&lt;/code&gt; can no longer run as an &lt;code&gt;X.org&lt;/code&gt; session.&lt;/p&gt;
&lt;p&gt;That does not mean old applications suddenly stop working. The official notes make it clear that &lt;code&gt;X.org&lt;/code&gt; applications can still run through the &lt;code&gt;XWayland&lt;/code&gt; compatibility layer. But if your workflow still depends on older graphics drivers, certain remote desktop methods, screen recording tools, or input method details, this is still something you should verify before upgrading.&lt;/p&gt;
&lt;h2 id=&#34;5-biggest-change-4-linux-kernel-70-and-the-lower-stack-move-forward-together&#34;&gt;5. Biggest change #4: Linux kernel 7.0 and the lower stack move forward together
&lt;/h2&gt;&lt;p&gt;The GA generic stack in &lt;code&gt;Ubuntu 26.04 LTS&lt;/code&gt; moves from &lt;code&gt;Linux 6.8&lt;/code&gt; to &lt;code&gt;Linux 7.0&lt;/code&gt;, and the HWE stack is also unified on &lt;code&gt;7.0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Among the lower-level changes highlighted by Ubuntu, the most relevant ones for general users and operators are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Crash dump is enabled by default on both desktop and server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sched_ext&lt;/code&gt; introduces a new scheduler extension model that lets developers implement scheduling policies with eBPF&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;linux-lowlatency&lt;/code&gt; binary package is being retired, replaced by &lt;code&gt;linux-generic&lt;/code&gt; plus the user-space &lt;code&gt;lowlatency-kernel&lt;/code&gt; package for low-latency tuning&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;amd64v3&lt;/code&gt; architecture variant is available as an option, but still opt-in by default&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your machine is relatively new, &lt;code&gt;amd64v3&lt;/code&gt; is worth keeping an eye on. The official notes give this enablement method:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;APT::Architecture-Variants &amp;#34;amd64v3&amp;#34;;&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo tee /etc/apt/apt.conf.d/99enable-amd64v3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt upgrade
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That said, it is not enabled automatically. Ubuntu is still prioritizing compatibility first.&lt;/p&gt;
&lt;h2 id=&#34;6-hardware-requirements-and-install-baseline&#34;&gt;6. Hardware requirements and install baseline
&lt;/h2&gt;&lt;p&gt;The official recommended baseline for Ubuntu Desktop 26.04 LTS is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;2 GHz&lt;/code&gt; dual-core processor or better&lt;/li&gt;
&lt;li&gt;At least &lt;code&gt;6 GB RAM&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;At least &lt;code&gt;25 GB&lt;/code&gt; of available storage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your machine is on the lighter side, the official recommendation is to consider Ubuntu flavors such as &lt;code&gt;Xubuntu&lt;/code&gt; or &lt;code&gt;Lubuntu&lt;/code&gt;.&lt;br&gt;
The server edition has a lower floor. The documentation notes it can start from &lt;code&gt;1.5 GB RAM&lt;/code&gt; and &lt;code&gt;4 GB&lt;/code&gt; of storage, though the real requirement still depends on your workload.&lt;/p&gt;
&lt;h2 id=&#34;7-who-should-prioritize-upgrading&#34;&gt;7. Who should prioritize upgrading
&lt;/h2&gt;&lt;p&gt;If you are already on &lt;code&gt;24.04 LTS&lt;/code&gt; and want the following, &lt;code&gt;26.04 LTS&lt;/code&gt; is worth a close look:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A full-generation desktop stack refresh instead of minor patching&lt;/li&gt;
&lt;li&gt;More mature &lt;code&gt;Wayland&lt;/code&gt; and display support&lt;/li&gt;
&lt;li&gt;A more up-to-date default application set&lt;/li&gt;
&lt;li&gt;A newer kernel with a longer support runway&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But if you still depend heavily on older &lt;code&gt;X11&lt;/code&gt; workflows, special drivers, or custom desktop extensions, or if your production environment is extremely conservative about changes, it is still best to do a compatibility pass before upgrading.&lt;/p&gt;
&lt;h2 id=&#34;8-one-line-summary&#34;&gt;8. One-line summary
&lt;/h2&gt;&lt;p&gt;The value of &lt;code&gt;Ubuntu 26.04 LTS&lt;/code&gt; is not one especially flashy headline feature. It is that Ubuntu has rolled two years of desktop, kernel, application, and compatibility progress into a new LTS baseline all at once.&lt;/p&gt;
&lt;p&gt;If you want the shortest possible judgment, it is this: &lt;strong&gt;this is an Ubuntu LTS release that feels broadly newer and more stable as a whole, rather than one built around a single standout feature.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;related-links&#34;&gt;Related links
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Official release notes: &lt;code&gt;https://documentation.ubuntu.com/release-notes/26.04/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Summary for LTS users: &lt;code&gt;https://documentation.ubuntu.com/release-notes/26.04/summary-for-lts-users/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Understanding the nftables Framework: Tables, Chains, Rules, and Sets</title>
        <link>https://knightli.com/en/2026/04/18/nftables-framework-concepts/</link>
        <pubDate>Sat, 18 Apr 2026 10:31:12 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/04/18/nftables-framework-concepts/</guid>
        <description>&lt;p&gt;When learning &lt;code&gt;nftables&lt;/code&gt;, it is easy to start with command details: how to add a rule, how to delete a handle, or how to write a port match. Commands matter, but if you understand the framework first, reading rules, troubleshooting, and designing rule sets become much easier.&lt;/p&gt;
&lt;p&gt;You can think of nftables as a layered structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;table&lt;/code&gt; isolates rule namespaces.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;family&lt;/code&gt; decides which network protocols the rules apply to.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chain&lt;/code&gt; decides at which stage rules are executed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rule&lt;/code&gt; defines the actual match and action.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, and &lt;code&gt;verdict map&lt;/code&gt; reduce repeated rules and make rule sets easier to maintain.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following sections explain these concepts layer by layer.&lt;/p&gt;
&lt;h2 id=&#34;table-rule-namespace&#34;&gt;table: Rule Namespace
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;table&lt;/code&gt; is the outermost rule container in nftables. Different tables are isolated from each other, so a common practice is to put related rules into the same table.&lt;/p&gt;
&lt;p&gt;For example, you can separate filtering rules, NAT rules, or custom testing rules. This keeps boundaries clear: when debugging, you know which group of rules you are changing; when cleaning up, you are less likely to delete unrelated content by mistake.&lt;/p&gt;
&lt;p&gt;A table itself does not directly process packets. The chain and rule objects inside the table are what actually participate in packet processing.&lt;/p&gt;
&lt;h2 id=&#34;family-which-protocols-the-rules-apply-to&#34;&gt;family: Which Protocols the Rules Apply To
&lt;/h2&gt;&lt;p&gt;When creating a table, you need to choose a &lt;code&gt;family&lt;/code&gt;. It determines what kind of packets the rules in the table apply to.&lt;/p&gt;
&lt;p&gt;Common families can be understood this way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip&lt;/code&gt;: handles IPv4 only.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip6&lt;/code&gt;: handles IPv6 only.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inet&lt;/code&gt;: handles both IPv4 and IPv6.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;arp&lt;/code&gt;: handles ARP.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bridge&lt;/code&gt;: handles bridge-layer traffic.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;netdev&lt;/code&gt;: closer to the network device ingress path, suitable for handling traffic at an earlier stage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For ordinary firewall rules, &lt;code&gt;inet&lt;/code&gt; is commonly used. It lets you keep IPv4 and IPv6 rules in the same table and avoids maintaining two similar rule structures.&lt;/p&gt;
&lt;h2 id=&#34;chain-where-rules-are-executed&#34;&gt;chain: Where Rules Are Executed
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;chain&lt;/code&gt; is a list of rules. After a packet enters a hook, it passes through the rules in the chain in order.&lt;/p&gt;
&lt;p&gt;Chains can roughly be divided into two types:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Base chain: attached to a hook in the kernel network path and actively called by the packet flow.&lt;/li&gt;
&lt;li&gt;Regular chain: not directly attached to a hook; it must be called by jumps from other rules.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A base chain usually specifies several key properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt;: the purpose of the chain, such as &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;nat&lt;/code&gt;, or &lt;code&gt;route&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hook&lt;/code&gt;: the processing stage, such as &lt;code&gt;prerouting&lt;/code&gt;, &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;forward&lt;/code&gt;, &lt;code&gt;output&lt;/code&gt;, or &lt;code&gt;postrouting&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;priority&lt;/code&gt;: when multiple chains exist on the same hook, this decides which runs first.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;policy&lt;/code&gt;: the default action when no rule matches, commonly &lt;code&gt;accept&lt;/code&gt; or &lt;code&gt;drop&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key point is that rules do not take effect just anywhere. The same rule has completely different meaning when placed in &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;forward&lt;/code&gt;, or &lt;code&gt;output&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;rule-match-conditions-plus-actions&#34;&gt;rule: Match Conditions Plus Actions
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;rule&lt;/code&gt; is where nftables actually makes decisions. It usually consists of two parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Match conditions: source IP, destination IP, protocol, port, interface, connection state, and so on.&lt;/li&gt;
&lt;li&gt;Actions: &lt;code&gt;accept&lt;/code&gt;, &lt;code&gt;drop&lt;/code&gt;, &lt;code&gt;reject&lt;/code&gt;, &lt;code&gt;counter&lt;/code&gt;, &lt;code&gt;jump&lt;/code&gt;, &lt;code&gt;return&lt;/code&gt;, and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rules are evaluated in order. After a packet matches an action that terminates processing, subsequent rules are no longer evaluated. If nothing matches, evaluation continues until the chain ends or the default policy is triggered.&lt;/p&gt;
&lt;p&gt;This is why rule order matters: more specific rules usually need to appear before broader rules, otherwise they may never get a chance to run.&lt;/p&gt;
&lt;h2 id=&#34;set-group-values-together&#34;&gt;set: Group Values Together
&lt;/h2&gt;&lt;p&gt;If you need to match many IP addresses, ports, or interfaces, writing many separate rules becomes hard to maintain. &lt;code&gt;set&lt;/code&gt; lets you manage a group of values of the same type in one place.&lt;/p&gt;
&lt;p&gt;For example, a group of trusted IPs, a group of blocked ports, or a group of addresses that need rate limiting can all be stored in a set. The rule only needs to check whether a value belongs to that set.&lt;/p&gt;
&lt;p&gt;The benefits of set are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fewer rules.&lt;/li&gt;
&lt;li&gt;Better readability.&lt;/li&gt;
&lt;li&gt;Easier element additions and removals later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a rule set contains many repeated conditions, it is usually time to consider set.&lt;/p&gt;
&lt;h2 id=&#34;map-map-a-matched-value-to-a-result&#34;&gt;map: Map a Matched Value to a Result
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;map&lt;/code&gt; can be understood as a lookup table. It returns a result based on an input value.&lt;/p&gt;
&lt;p&gt;For example, different ports can map to different marks, or different addresses can map to different processing parameters. Compared with writing many if/else-style rules, map is more centralized and easier to maintain.&lt;/p&gt;
&lt;p&gt;set answers &amp;ldquo;is this value in the collection&amp;rdquo;; map answers &amp;ldquo;what result corresponds to this value&amp;rdquo;.&lt;/p&gt;
&lt;h2 id=&#34;verdict-map-map-a-matched-value-to-an-action&#34;&gt;verdict map: Map a Matched Value to an Action
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;verdict map&lt;/code&gt; is an important use of map: it maps a matched value to a verdict, which means a rule action.&lt;/p&gt;
&lt;p&gt;For example, different IP ranges can correspond to &lt;code&gt;accept&lt;/code&gt;, &lt;code&gt;drop&lt;/code&gt;, or jumps to different chains. This can compress many branches into one structure.&lt;/p&gt;
&lt;p&gt;When a rule set grows more complex, verdict map is very useful. It reduces repeated rules and expresses policy more like a table rather than a long list of conditional statements.&lt;/p&gt;
&lt;h2 id=&#34;designing-rules-from-the-concepts&#34;&gt;Designing Rules from the Concepts
&lt;/h2&gt;&lt;p&gt;When designing nftables rules, you can think in this order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First decide which &lt;code&gt;family&lt;/code&gt; the rules belong to.&lt;/li&gt;
&lt;li&gt;Then decide which &lt;code&gt;table&lt;/code&gt; they should go into.&lt;/li&gt;
&lt;li&gt;Choose the proper &lt;code&gt;hook&lt;/code&gt; and &lt;code&gt;chain&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Write the concrete &lt;code&gt;rule&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If there are many repeated conditions, introduce &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, or &lt;code&gt;verdict map&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Rules written this way are easier to maintain and easier to troubleshoot.&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary
&lt;/h2&gt;&lt;p&gt;nftables concepts are not complicated, but the hierarchy matters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;table defines rule boundaries.&lt;/li&gt;
&lt;li&gt;family defines protocol scope.&lt;/li&gt;
&lt;li&gt;chain defines execution position.&lt;/li&gt;
&lt;li&gt;rule defines matching and action.&lt;/li&gt;
&lt;li&gt;set, map, and verdict map manage complexity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Understand these concepts first, then look at concrete commands. That is more reliable than memorizing commands directly. Especially after a rule set grows, clear concepts help you determine whether a problem is in protocol scope, execution stage, rule order, or the match condition itself.&lt;/p&gt;
&lt;h2 id=&#34;references&#34;&gt;References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.redhat.com/zh-cn/documentation/red_hat_enterprise_linux/10/html/configuring_firewalls_and_packet_filters/concepts-in-the-nftables-framework&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://docs.redhat.com/zh-cn/documentation/red_hat_enterprise_linux/10/html/configuring_firewalls_and_packet_filters/concepts-in-the-nftables-framework&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>nftables Quick Start: Tables, Chains, Rules, and Common Operations</title>
        <link>https://knightli.com/en/2026/04/18/nftables-quick-start/</link>
        <pubDate>Sat, 18 Apr 2026 10:22:07 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/04/18/nftables-quick-start/</guid>
        <description>&lt;p&gt;&lt;code&gt;nftables&lt;/code&gt; is a common packet filtering and firewall rule management tool on Linux. If you only need device access control, traffic counters, port matching, or basic rate limiting, you do not need to learn the entire rule system at once. Start with three concepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;table&lt;/code&gt;: a container for rules.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chain&lt;/code&gt;: where rules are evaluated, usually attached to a hook.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rule&lt;/code&gt;: the actual matching condition and action.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This article outlines a minimal workflow that is suitable for testing first in a safe environment.&lt;/p&gt;
&lt;h2 id=&#34;basic-structure&#34;&gt;Basic Structure
&lt;/h2&gt;&lt;p&gt;Prepare a few variables first. The following commands reuse them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;customtable
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;chain&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;custom_control
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;drop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;192.168.18.251
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;mac&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;00:00:01:02:03:04
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Create an &lt;code&gt;inet&lt;/code&gt; table that supports both IPv4 and IPv6:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add table inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then create a chain attached to the &lt;code&gt;forward&lt;/code&gt; stage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; filter hook forward priority 0&lt;span class=&#34;se&#34;&gt;\;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Here, &lt;code&gt;type filter&lt;/code&gt; means this is a filtering rule chain, and &lt;code&gt;hook forward&lt;/code&gt; means it processes forwarded packets.&lt;/p&gt;
&lt;h2 id=&#34;common-matching-methods&#34;&gt;Common Matching Methods
&lt;/h2&gt;&lt;p&gt;Match by source IP. This is usually useful for the upload direction:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ip saddr &lt;span class=&#34;nv&#34;&gt;$ip&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Match by destination IP. This is usually useful for the download direction:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ip daddr &lt;span class=&#34;nv&#34;&gt;$ip&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;When matching by MAC address, &lt;code&gt;ether saddr&lt;/code&gt; can be used to control upstream traffic:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ether saddr &lt;span class=&#34;nv&#34;&gt;$mac&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Note that in networks involving bridging, forwarding, or address translation, downstream packets may not always be reliably filtered by destination MAC. For device access control, start by validating &lt;code&gt;ether saddr&lt;/code&gt; or IP-based rules first.&lt;/p&gt;
&lt;p&gt;To match ports, you can cover both TCP and UDP:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt; tcp, udp &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; dport &lt;span class=&#34;m&#34;&gt;22&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;To match a port range, use a comparison expression:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; tcp dport &lt;span class=&#34;se&#34;&gt;\&amp;gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;count-traffic-for-one-device&#34;&gt;Count Traffic for One Device
&lt;/h2&gt;&lt;p&gt;If you only want to count upload and download traffic for an IP address, use &lt;code&gt;counter return&lt;/code&gt;. After a match, it records the counter and returns, which can reduce further matching overhead when more statistic rules exist later.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ip saddr &lt;span class=&#34;nv&#34;&gt;$ip&lt;/span&gt; counter &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ip daddr &lt;span class=&#34;nv&#34;&gt;$ip&lt;/span&gt; counter &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;View the statistics:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft list chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If you need to see the &lt;code&gt;handle&lt;/code&gt; for each rule, add &lt;code&gt;-a&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft -a list chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;handle&lt;/code&gt; is important because nftables usually relies on it to delete a single rule.&lt;/p&gt;
&lt;h2 id=&#34;basic-rate-limiting&#34;&gt;Basic Rate Limiting
&lt;/h2&gt;&lt;p&gt;Rate limiting can be done with &lt;code&gt;limit rate over&lt;/code&gt;. For example, limit traffic over a specified rate by MAC address:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;rate&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;unit&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;mbytes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ether saddr &lt;span class=&#34;nv&#34;&gt;$mac&lt;/span&gt; limit rate over &lt;span class=&#34;nv&#34;&gt;$rate&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$unit&lt;/span&gt;/second drop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Here, &lt;code&gt;mbytes&lt;/code&gt; and &lt;code&gt;kbytes&lt;/code&gt; can be understood as the usual M and K units. You do not need to manually multiply by 8. In practice, start with a more relaxed value, confirm the matching direction and effect, then tighten it if needed.&lt;/p&gt;
&lt;h2 id=&#34;delete-and-clean-up-rules&#34;&gt;Delete and Clean Up Rules
&lt;/h2&gt;&lt;p&gt;First list rules with &lt;code&gt;handle&lt;/code&gt; values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft -a list chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then delete a rule by handle:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft delete rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; handle &amp;lt;handle&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Flush a chain:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft flush chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Delete a chain:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft delete chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Delete the entire table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft delete table inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;During daily debugging, only clean up the table you created yourself. Avoid directly changing tables automatically generated by the system or other services. This makes rollback easier even if a rule is written incorrectly.&lt;/p&gt;
&lt;h2 id=&#34;usage-notes&#34;&gt;Usage Notes
&lt;/h2&gt;&lt;p&gt;When using nftables, it is often safer to create your own independent table and chain first. This has two benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Your rules are less likely to mix with existing system rules.&lt;/li&gt;
&lt;li&gt;Debugging, flushing, and deletion are safer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After writing rules, always use &lt;code&gt;nft list chain&lt;/code&gt; to check actual matching behavior. MAC, interface, port, and rate-limit rules may behave differently across devices, bridge setups, and system versions. Small-scope testing is safer than writing complex rules all at once.&lt;/p&gt;
&lt;h2 id=&#34;references&#34;&gt;References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.right.com.cn/forum/thread-8369750-1-1.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.right.com.cn/forum/thread-8369750-1-1.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>go2rtc with Xiaomi Camera RTSP: Feed NVR, HomeKit, and Frigate</title>
        <link>https://knightli.com/en/2026/04/11/go2rtc-xiaomi-rtsp-nvr-homekit-frigate/</link>
        <pubDate>Sat, 11 Apr 2026 08:14:47 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/04/11/go2rtc-xiaomi-rtsp-nvr-homekit-frigate/</guid>
        <description>&lt;p&gt;This note shows how to use &lt;code&gt;go2rtc&lt;/code&gt; to pull Xiaomi camera streams directly and reuse them across NVR, HomeKit, and Frigate.&lt;/p&gt;
&lt;h2 id=&#34;docker-deployment-example&#34;&gt;Docker deployment example
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;go2rtc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;container_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;go2rtc&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;alexxit/go2rtc:master-hardware&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;restart&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;always&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;network_mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;privileged&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;environment&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;TZ=Asia/Shanghai&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;volumes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;/vol1/1000/docker/go2rtc:/config&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;go2rtc web UI:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;http://192.168.3.217:1984/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;stream-config-example&#34;&gt;Stream config example
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;streams&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;micam1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;xiaomi://xxx&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#H265转H264,Homekit预览会用到&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#micam1_h264:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#- ffmpeg:micam1#video=h264#width=1280#height=720#hardware#raw=-r 15&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;micam2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;xiaomi://xxx&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;micam3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;xiaomi://xxx&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;RTSP URL format:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rtsp://192.168.3.217:8554/micam1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;quality-and-parameters&#34;&gt;Quality and parameters
&lt;/h2&gt;&lt;p&gt;Quality is controlled with values from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;5&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0&lt;/code&gt; usually means auto&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1&lt;/code&gt; means &lt;code&gt;sd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2&lt;/code&gt; means &lt;code&gt;hd&lt;/code&gt; (default in go2rtc)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some newer models may map HD to &lt;code&gt;3&lt;/code&gt;. Older models can break codec settings at &lt;code&gt;3&lt;/code&gt;, so avoid applying one fixed value to all devices.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;subtype=hd/sd/auto/0-5&lt;/code&gt; to set quality:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;streams&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;xiaomi1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;xiaomi://***&amp;amp;subtype=sd&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For dual-lens cameras, use second channel with &lt;code&gt;channel=2&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;streams&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;xiaomi1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;xiaomi://***&amp;amp;channel=2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;summary&#34;&gt;Summary
&lt;/h2&gt;&lt;p&gt;Once go2rtc is in front, one RTSP source can serve NVR recording, Frigate detection, and HomeKit preview at the same time, which simplifies maintenance.&lt;/p&gt;
&lt;h2 id=&#34;references&#34;&gt;References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Camera support list: &lt;a class=&#34;link&#34; href=&#34;https://github.com/AlexxIT/go2rtc/issues/1982&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/AlexxIT/go2rtc/issues/1982&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official Xiaomi notes: &lt;a class=&#34;link&#34; href=&#34;https://github.com/AlexxIT/go2rtc/blob/master/internal/xiaomi/README.md&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/AlexxIT/go2rtc/blob/master/internal/xiaomi/README.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Docker image: &lt;a class=&#34;link&#34; href=&#34;https://hub.docker.com/r/alexxit/go2rtc&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://hub.docker.com/r/alexxit/go2rtc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Windows Task Manager data stops updating: the refresh speed is usually set to Paused</title>
        <link>https://knightli.com/en/2026/04/09/windows-task-manager-data-paused/</link>
        <pubDate>Thu, 09 Apr 2026 18:15:53 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/04/09/windows-task-manager-data-paused/</guid>
        <description>&lt;p&gt;Sometimes when you open Windows Task Manager, the data on the &lt;code&gt;Processes&lt;/code&gt; or &lt;code&gt;Performance&lt;/code&gt; tab appears frozen. CPU, memory, disk, or network values may stay unchanged for a long time. At first glance this can look like a system problem, but in reality running programs, network traffic, and resource usage are still changing normally.&lt;/p&gt;
&lt;p&gt;In most cases, the system is not actually stuck. The more likely reason is that Task Manager&amp;rsquo;s refresh speed has been changed to &lt;code&gt;Paused&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;symptoms&#34;&gt;Symptoms
&lt;/h2&gt;&lt;p&gt;Common signs include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU, memory, and other values on the &lt;code&gt;Processes&lt;/code&gt; tab stop changing&lt;/li&gt;
&lt;li&gt;Graphs on the &lt;code&gt;Performance&lt;/code&gt; tab no longer update&lt;/li&gt;
&lt;li&gt;Programs are clearly still running, but Task Manager looks frozen&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is an example of what the issue looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://knightli.com/2026/04/09/windows-task-manager-data-paused/1.png&#34;
	width=&#34;639&#34;
	height=&#34;546&#34;
	srcset=&#34;https://knightli.com/2026/04/09/windows-task-manager-data-paused/1_hu_b54b1db143639c67.png 480w, https://knightli.com/2026/04/09/windows-task-manager-data-paused/1_hu_133bff4e7ebfe2ef.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Example of Task Manager data not updating&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;117&#34;
		data-flex-basis=&#34;280px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;cause&#34;&gt;Cause
&lt;/h2&gt;&lt;p&gt;Task Manager lets you adjust the &lt;code&gt;Update speed&lt;/code&gt;, with options such as High, Normal, Low, or Paused.&lt;/p&gt;
&lt;p&gt;If this setting is changed to &lt;code&gt;Paused&lt;/code&gt;, the statistics shown in the interface stop refreshing. That is why CPU, memory, or network information can appear to be completely frozen.&lt;/p&gt;
&lt;p&gt;As shown below, this option is usually available from the &lt;code&gt;View&lt;/code&gt; menu in Task Manager:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://knightli.com/2026/04/09/windows-task-manager-data-paused/2.png&#34;
	width=&#34;642&#34;
	height=&#34;547&#34;
	srcset=&#34;https://knightli.com/2026/04/09/windows-task-manager-data-paused/2_hu_3020d576b0c86412.png 480w, https://knightli.com/2026/04/09/windows-task-manager-data-paused/2_hu_9f84b87ce1e21e95.png 1024w&#34;
	loading=&#34;lazy&#34;
	
		alt=&#34;Task Manager update speed set to Paused&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;117&#34;
		data-flex-basis=&#34;281px&#34;
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;fix&#34;&gt;Fix
&lt;/h2&gt;&lt;p&gt;Check the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open Task Manager&lt;/li&gt;
&lt;li&gt;Click the &lt;code&gt;View&lt;/code&gt; menu&lt;/li&gt;
&lt;li&gt;Find &lt;code&gt;Update speed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Check whether it is currently set to &lt;code&gt;Paused&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Change it back to &lt;code&gt;Normal&lt;/code&gt; or &lt;code&gt;High&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After that, watch the &lt;code&gt;Processes&lt;/code&gt; or &lt;code&gt;Performance&lt;/code&gt; tab again. In most cases, the data will start updating normally right away.&lt;/p&gt;
&lt;h2 id=&#34;additional-notes&#34;&gt;Additional notes
&lt;/h2&gt;&lt;p&gt;If the data still does not refresh after switching back to &lt;code&gt;Normal&lt;/code&gt;, check a few other possibilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Whether you are using system-tuning tools or third-party performance monitoring software&lt;/li&gt;
&lt;li&gt;Whether you are connected through a remote session and the interface is not refreshing correctly&lt;/li&gt;
&lt;li&gt;Whether Task Manager itself is stuck, in which case you can close it and open it again&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That said, in most cases this issue is simply caused by &lt;code&gt;Update speed&lt;/code&gt; being accidentally set to &lt;code&gt;Paused&lt;/code&gt;, so checking that first is usually the fastest fix.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Two Ways to Remotely Access Feiniu NAS and Their Comparison</title>
        <link>https://knightli.com/en/2026/04/04/fnos-remote-access-public-ip-vs-fn-connect/</link>
        <pubDate>Sat, 04 Apr 2026 11:00:00 +0800</pubDate>
        
        <guid>https://knightli.com/en/2026/04/04/fnos-remote-access-public-ip-vs-fn-connect/</guid>
        <description>&lt;p&gt;There are two common ways to remotely access a Feiniu NAS:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Direct public IP access&lt;/li&gt;
&lt;li&gt;FN Connect remote access service&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Below is a practical guide organized by &amp;ldquo;how to use + key notes + best-fit scenarios.&amp;rdquo;&lt;/p&gt;
&lt;h2 id=&#34;option-1-direct-public-ip-access&#34;&gt;Option 1: Direct Public IP Access
&lt;/h2&gt;&lt;p&gt;This is suitable when your home network has a public IP and you can configure port forwarding on the router.&lt;br&gt;
After that, you can access it by entering the public IPv4/IPv6 address and port in a browser or in the Feiniu App.&lt;br&gt;
You can also set up DDNS and access via domain name.&lt;/p&gt;
&lt;h3 id=&#34;notes&#34;&gt;Notes
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Default ports for Feiniu private cloud fnOS:
&lt;code&gt;HTTP = 8000&lt;/code&gt;, &lt;code&gt;HTTPS = 8001&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If port forwarding is configured, the access URL must include the port number; otherwise, access will fail.&lt;/li&gt;
&lt;li&gt;Direct public IP access usually has no extra relay, so speed loss is lower.&lt;/li&gt;
&lt;li&gt;If security certificates are not configured properly, HTTP is plaintext. Use only in trusted network environments.&lt;/li&gt;
&lt;li&gt;Many broadband providers block common ports such as 80 and 8080. If common ports do not work, try less common ports.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;option-2-fn-connect-remote-access-service&#34;&gt;Option 2: FN Connect Remote Access Service
&lt;/h2&gt;&lt;p&gt;FN Connect is a remote-access service provided by Feiniu.&lt;br&gt;
After enabling it, you get a unique FN ID to identify your Feiniu NAS and access it remotely through the corresponding method.&lt;/p&gt;
&lt;h3 id=&#34;notes-1&#34;&gt;Notes
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;FN Connect requires you to register or sign in with a Feiniu account.&lt;/li&gt;
&lt;li&gt;FN Connect provides an SSL certificate for the subdomain mapped to your FN ID, enabling secure HTTPS access.&lt;/li&gt;
&lt;li&gt;FN Connect automatically chooses a better connection method based on your current network environment.&lt;/li&gt;
&lt;li&gt;When direct public access is available, the web client can choose whether to use direct public IP access.&lt;/li&gt;
&lt;li&gt;FN Connect relay forwarding has traffic cost, so rate limiting applies.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;comparison-of-the-two-methods&#34;&gt;Comparison of the Two Methods
&lt;/h2&gt;&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;Dimension&lt;/th&gt;
          &lt;th&gt;Direct Public IP Access&lt;/th&gt;
          &lt;th&gt;FN Connect&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;Getting started&lt;/td&gt;
          &lt;td&gt;Requires public IP + router port forwarding&lt;/td&gt;
          &lt;td&gt;Lower barrier with account login and guided setup&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Access speed&lt;/td&gt;
          &lt;td&gt;Usually faster with a more direct path&lt;/td&gt;
          &lt;td&gt;Close to direct mode when direct; possibly limited when relayed&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Security&lt;/td&gt;
          &lt;td&gt;Depends on your own certificate and exposure strategy&lt;/td&gt;
          &lt;td&gt;Certificate support by default, easier HTTPS setup, depends on Feiniu&amp;rsquo;s own security&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Maintenance cost&lt;/td&gt;
          &lt;td&gt;You maintain network and security settings yourself&lt;/td&gt;
          &lt;td&gt;Lower day-to-day maintenance effort&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;Best for&lt;/td&gt;
          &lt;td&gt;Users with networking experience and performance focus&lt;/td&gt;
          &lt;td&gt;Users who prioritize ease of use and stability&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;recommendations&#34;&gt;Recommendations
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;If you are comfortable with networking and want higher bandwidth/lower latency, prioritize direct public IP access.&lt;/li&gt;
&lt;li&gt;If you care more about ease of use and secure access experience, prioritize FN Connect.&lt;/li&gt;
&lt;li&gt;In practice, you can mix both: use FN Connect by default, and switch to direct public IP when conditions allow.&lt;/li&gt;
&lt;/ol&gt;
</description>
        </item>
        <item>
        <title>Automatically Renew Let&#39;s Encrypt Certificates on Ubuntu (Certbot &#43; Nginx)</title>
        <link>https://knightli.com/en/2026/04/03/certbot-auto-renew-nginx/</link>
        <pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate>
        
        <guid>https://knightli.com/en/2026/04/03/certbot-auto-renew-nginx/</guid>
        <description>&lt;p&gt;Let&amp;rsquo;s Encrypt certificates are valid for only 90 days, so production sites should always enable automatic renewal to avoid HTTPS downtime.&lt;/p&gt;
&lt;p&gt;If you already issued the certificate with Certbot, there are usually two things left:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Configure a scheduled renewal task&lt;/li&gt;
&lt;li&gt;Verify the renewal workflow actually works&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;first-check-whether-certbot-already-created-a-scheduler&#34;&gt;First, Check Whether Certbot Already Created a Scheduler
&lt;/h2&gt;&lt;p&gt;Depending on your distro, Certbot may already install a scheduler (for example, a &lt;code&gt;systemd timer&lt;/code&gt; or &lt;code&gt;/etc/cron.d/certbot&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;You can check with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemctl list-timers &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep certbot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If a valid timer already exists, you usually do not need an extra crontab entry.&lt;/p&gt;
&lt;h2 id=&#34;add-a-crontab-job-manually-recommended-example&#34;&gt;Add a Crontab Job Manually (Recommended Example)
&lt;/h2&gt;&lt;p&gt;If you prefer managing renewal explicitly, edit root crontab:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo crontab -e
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Add this line (runs daily at 03:00):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 3 * * * certbot renew --pre-hook &amp;#34;systemctl stop nginx&amp;#34; --post-hook &amp;#34;systemctl start nginx&amp;#34; &amp;gt;&amp;gt; /tmp/certbot-renew.log 2&amp;gt;&amp;amp;1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;What it means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0 3 * * *&lt;/code&gt;: run at 03:00 every day&lt;/li&gt;
&lt;li&gt;&lt;code&gt;certbot renew&lt;/code&gt;: renew certificates that are close to expiration&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--pre-hook&lt;/code&gt;: stop Nginx before renewal (common for standalone mode)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--post-hook&lt;/code&gt;: start Nginx after renewal&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&amp;gt; /tmp/certbot-renew.log 2&amp;gt;&amp;amp;1&lt;/code&gt;: append logs for troubleshooting&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;run-a-dry-test-before-relying-on-cron&#34;&gt;Run a Dry Test Before Relying on Cron
&lt;/h2&gt;&lt;p&gt;After adding the task, validate the full flow manually:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo certbot renew --dry-run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If dry-run succeeds, you can safely rely on the scheduled job.&lt;/p&gt;
&lt;h2 id=&#34;common-notes&#34;&gt;Common Notes
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;If you use the &lt;code&gt;webroot&lt;/code&gt; or &lt;code&gt;nginx&lt;/code&gt; plugin, you often do not need to stop Nginx. In many setups, reloading Nginx after renewal is enough:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;certbot renew --deploy-hook &lt;span class=&#34;s2&#34;&gt;&amp;#34;systemctl reload nginx&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;certbot renew&lt;/code&gt; only performs actual renewal near expiration, so running it daily is normal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For long-term maintenance, consider writing logs to a persistent path such as &lt;code&gt;/var/log/letsencrypt/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary
&lt;/h2&gt;&lt;p&gt;Reliable certificate auto-renewal is not just about writing a command. The key is confirming the workflow can run end to end.&lt;/p&gt;
&lt;p&gt;A stable setup is usually just these three steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check whether system-level scheduling already exists&lt;/li&gt;
&lt;li&gt;Add cron if needed and keep logs&lt;/li&gt;
&lt;li&gt;Validate once with &lt;code&gt;--dry-run&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
        </item>
        <item>
        <title>How to Verify Whether Certbot Can Renew a Let&#39;s Encrypt Certificate Successfully</title>
        <link>https://knightli.com/en/2022/12/08/certbot-renewal-dry-run/</link>
        <pubDate>Thu, 08 Dec 2022 00:00:00 +0000</pubDate>
        
        <guid>https://knightli.com/en/2022/12/08/certbot-renewal-dry-run/</guid>
        <description>&lt;p&gt;After using Certbot to issue a free Let&amp;rsquo;s Encrypt certificate, the most important follow-up question is whether automatic renewal will work.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s Encrypt certificates are valid for a limited time. If renewal fails silently, HTTPS may break after the certificate expires. Certbot provides a dry-run mode that can simulate the renewal process without replacing the real certificate.&lt;/p&gt;
&lt;h2 id=&#34;use-certbot-dry-run&#34;&gt;Use Certbot Dry Run
&lt;/h2&gt;&lt;p&gt;Run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;certbot renew --dry-run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This command asks Certbot to simulate certificate renewal. It checks whether the current account, domain validation method, web server integration and renewal configuration can still complete the process.&lt;/p&gt;
&lt;p&gt;If the command succeeds, Certbot prints a success message similar to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Congratulations, all simulated renewals succeeded
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That means the renewal workflow is currently valid.&lt;/p&gt;
&lt;h2 id=&#34;what-dry-run-checks&#34;&gt;What Dry Run Checks
&lt;/h2&gt;&lt;p&gt;The dry run does not simply check the certificate file. It also verifies the renewal path:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;whether the domain can still be validated;&lt;/li&gt;
&lt;li&gt;whether the web server configuration allows the validation challenge;&lt;/li&gt;
&lt;li&gt;whether Certbot can read the existing renewal configuration;&lt;/li&gt;
&lt;li&gt;whether the certificate account and plugins are available;&lt;/li&gt;
&lt;li&gt;whether the deploy/reload hooks can run.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes it more useful than only checking the certificate expiration date.&lt;/p&gt;
&lt;h2 id=&#34;common-failure-causes&#34;&gt;Common Failure Causes
&lt;/h2&gt;&lt;p&gt;If &lt;code&gt;certbot renew --dry-run&lt;/code&gt; fails, common causes include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the domain no longer points to the server;&lt;/li&gt;
&lt;li&gt;port 80 or 443 is blocked;&lt;/li&gt;
&lt;li&gt;Nginx or Apache configuration changed;&lt;/li&gt;
&lt;li&gt;the webroot path no longer matches the renewal configuration;&lt;/li&gt;
&lt;li&gt;firewall rules block Let&amp;rsquo;s Encrypt validation;&lt;/li&gt;
&lt;li&gt;the Certbot plugin used during issuance is missing;&lt;/li&gt;
&lt;li&gt;deploy hooks or reload commands fail.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fix the error reported by Certbot, then run the dry run again.&lt;/p&gt;
&lt;h2 id=&#34;check-the-renewal-timer&#34;&gt;Check The Renewal Timer
&lt;/h2&gt;&lt;p&gt;On systems using systemd, Certbot usually installs a timer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemctl status certbot.timer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;You can list scheduled timers with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;systemctl list-timers &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep certbot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If the timer is active and dry-run renewal succeeds, automatic renewal should work normally.&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary
&lt;/h2&gt;&lt;p&gt;To verify whether Certbot can renew a Let&amp;rsquo;s Encrypt certificate, the most direct command is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;certbot renew --dry-run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Run it after changing web server configuration, firewall rules, domain DNS or Certbot plugins. This simple check can prevent an expired certificate from breaking HTTPS unexpectedly.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Use OpenWrt and WireGuard to Connect Two Remote LANs over the Internet</title>
        <link>https://knightli.com/en/2022/04/14/openwrt-wireguard-connect-two-lans/</link>
        <pubDate>Thu, 14 Apr 2022 00:00:00 +0000</pubDate>
        
        <guid>https://knightli.com/en/2022/04/14/openwrt-wireguard-connect-two-lans/</guid>
        <description>&lt;p&gt;WireGuard can be used on OpenWrt routers to connect two LANs in different locations. After configuration, devices on both sides can access each other as if they were connected through a private routed network.&lt;/p&gt;
&lt;p&gt;This is useful for home labs, NAS access, remote monitoring, backup synchronization and small office interconnection.&lt;/p&gt;
&lt;h2 id=&#34;basic-topology&#34;&gt;Basic Topology
&lt;/h2&gt;&lt;p&gt;Assume there are two sites:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Site A LAN: 192.168.1.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Site B LAN: 192.168.2.0/24
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;WireGuard tunnel: 10.10.10.0/24
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Each OpenWrt router runs WireGuard. One side can act as the peer with a public endpoint, or both sides can connect through a reachable server.&lt;/p&gt;
&lt;h2 id=&#34;install-wireguard&#34;&gt;Install WireGuard
&lt;/h2&gt;&lt;p&gt;On OpenWrt, install the required packages:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;opkg update
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;opkg install wireguard-tools luci-proto-wireguard
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;After installation, the LuCI web interface can configure WireGuard interfaces.&lt;/p&gt;
&lt;h2 id=&#34;create-keys&#34;&gt;Create Keys
&lt;/h2&gt;&lt;p&gt;Generate private and public keys for each side:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;wg genkey &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; tee privatekey &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; wg pubkey &amp;gt; publickey
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Keep private keys secret. Exchange only public keys between the two routers.&lt;/p&gt;
&lt;h2 id=&#34;configure-the-tunnel&#34;&gt;Configure The Tunnel
&lt;/h2&gt;&lt;p&gt;Create a WireGuard interface on each router, for example &lt;code&gt;wg0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Example tunnel addresses:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Site A wg0: 10.10.10.1/24
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Site B wg0: 10.10.10.2/24
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For Site A, add Site B as a peer and set allowed IPs to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10.10.10.2/32
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;192.168.2.0/24
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For Site B, add Site A as a peer and set allowed IPs to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;10.10.10.1/32
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;192.168.1.0/24
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;These routes tell each router which remote subnet should go through the WireGuard tunnel.&lt;/p&gt;
&lt;h2 id=&#34;firewall-and-routing&#34;&gt;Firewall And Routing
&lt;/h2&gt;&lt;p&gt;Create or assign a firewall zone for the WireGuard interface. Allow forwarding between LAN and WireGuard zones according to your policy.&lt;/p&gt;
&lt;p&gt;At minimum, each side needs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LAN to WireGuard forwarding;&lt;/li&gt;
&lt;li&gt;WireGuard to LAN forwarding;&lt;/li&gt;
&lt;li&gt;UDP port open for WireGuard on the side with a public endpoint;&lt;/li&gt;
&lt;li&gt;correct allowed IPs for the remote subnet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If NAT is not required, routed access is cleaner. Each LAN should know that the other LAN is reachable through the WireGuard router.&lt;/p&gt;
&lt;h2 id=&#34;test-connectivity&#34;&gt;Test Connectivity
&lt;/h2&gt;&lt;p&gt;After both sides are configured, test the tunnel address first:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ping 10.10.10.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ping 10.10.10.2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then test a host in the remote LAN:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ping 192.168.2.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If tunnel IPs work but LAN hosts fail, check firewall forwarding and remote subnet routes.&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary
&lt;/h2&gt;&lt;p&gt;OpenWrt plus WireGuard is a lightweight way to connect two remote LANs. The important points are key exchange, tunnel addresses, allowed IPs, firewall forwarding and correct routing between the two LAN segments.&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
