<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ClF3&#39;s blog</title>
        <link>https://blog.clf3.org/</link>
        <description>Recent content on ClF3&#39;s blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-us</language>
        <lastBuildDate>Wed, 09 Apr 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.clf3.org/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Compile and Install a Linux Kernel in Asahi Linux</title>
        <link>https://blog.clf3.org/post/asahi-kernel-compile/</link>
        <pubDate>Tue, 25 Mar 2025 13:48:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/asahi-kernel-compile/</guid>
        <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Install build tools, download the kernel source, copy &lt;code&gt;.config&lt;/code&gt;, &lt;code&gt;make&lt;/code&gt;, install everything, fix DTB path, run &lt;code&gt;update-m1n1&lt;/code&gt;, &lt;strong&gt;do not reboot without verifying DTB fix!&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;h2 id=&#34;1-preparation&#34;&gt;1. Preparation
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install Asahi Linux (if not already installed):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If Asahi Linux is not already installed, run the following command on macOS and follow the instructions to set it up.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl https://alx.sh | sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Download the kernel source:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Download the appropriate version from the &lt;a class=&#34;link&#34; href=&#34;https://gitlab.com/fedora-asahi/kernel-asahi&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Fedora Asahi Repo&lt;/a&gt;, then extract and enter the directory:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar -xf kernel-asahi-kernel-6.12.1-404.asahi.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd kernel-asahi-kernel-6.12.1-404.asahi/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install the building essentials:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To compile the kernel, you’ll first need to install the required build tools:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo dnf install make automake gcc gcc-c++ openssl-devel ncurses-devel flex bison
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;2-config-and-compile&#34;&gt;2. Config and Compile
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Copy the current kernel configuration:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Copy your existing kernel configuration as a starting point and then open it in menuconfig to adjust settings if needed.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo cp /boot/config-&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;uname -r&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt; .config
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make menuconfig
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Compile the kernel:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Use the &lt;code&gt;-j&lt;/code&gt; flag (adjust the number according to your CPU cores) for faster compilation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make -j &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install the modules, device trees, VDSO and kernel:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Run the following command to install modules, device trees, VDSO, and the kernel itself:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo make modules_install dtbs_install vdso_install install
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But the installation is not finished yet. If you reboot now, you&amp;rsquo;ll end up &lt;strong&gt;unbootable&lt;/strong&gt;. Because after running &lt;code&gt;dtbs_install&lt;/code&gt;, the device tree blob (dtb) files are installed in the wrong location.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;3-deal-with-dtb-problems&#34;&gt;3. Deal with DTB Problems
&lt;/h2&gt;&lt;p&gt;The default Makefile creates a symlink from &lt;code&gt;/boot/dtb&lt;/code&gt; to &lt;code&gt;/boot/dtb-$(kernel-version)&lt;/code&gt;, but actually installs the files in &lt;code&gt;/boot/dtbs/$(kernel-version)&lt;/code&gt;. This mismatch makes the symlink invalid, causing the system to fail to locate DTB files at boot. Rebooting without fixing this will result in &lt;strong&gt;missing peripheral drivers&lt;/strong&gt; and potentially an &lt;strong&gt;unbootable system&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To fix this, move the directory to match the expected name (replace 6.12.1 with your kernel version):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo mv /boot/dtbs/6.12.1/ /boot/dtb-6.12.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;4-update-m1n1&#34;&gt;4. Update m1n1
&lt;/h2&gt;&lt;p&gt;After every kernel upgrade, you need to update m1n1 to ensure the boot firmware is correctly aligned with your new kernel:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo update-m1n1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Refer to the &lt;a class=&#34;link&#34; href=&#34;https://asahilinux.org/docs/alt/installing-gentoo/#updating-u-boot-and-m1n1&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Asahi Linux Docs&lt;/a&gt; for more details on why this step is necessary.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;5-done-and-reboot&#34;&gt;5. Done and Reboot
&lt;/h2&gt;&lt;p&gt;Before rebooting, &lt;strong&gt;double-check that you have completed every step&lt;/strong&gt;. Skipping any part could result in an unbootable system or boot loops. A critical note: due to issues like the absence of USB keyboard support in GRUB (see &lt;a class=&#34;link&#34; href=&#34;https://github.com/leifliddy/asahi-fedora-builder/issues/3&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;this issue&lt;/a&gt;), recovering from such a scenario can be very challenging.&lt;/p&gt;
&lt;p&gt;When you’re certain that everything is in place, you can safely reboot:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>Utilizing PMU Event Counters on Apple M3 and M4</title>
        <link>https://blog.clf3.org/post/pmu-event-counters/</link>
        <pubDate>Sat, 15 Mar 2025 12:53:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/pmu-event-counters/</guid>
        <description>&lt;p&gt;The &lt;a class=&#34;link&#34; href=&#34;https://asahilinux.org/docs/hw/cpu/system-registers/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Asahi Linux Docs&lt;/a&gt; include detailed information for PMU registers on Apple M1 and M2 processors. However, on M3 and M4, there are notable differences.&lt;/p&gt;
&lt;h2 id=&#34;register-definition&#34;&gt;Register Definition
&lt;/h2&gt;&lt;p&gt;The PMU register definitions are as follows, according to the &lt;a class=&#34;link&#34; href=&#34;https://asahilinux.org/docs/hw/cpu/system-registers/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Asahi Linux Docs&lt;/a&gt; and my experiments on M3 and M4 chips.&lt;/p&gt;
&lt;h3 id=&#34;sys_apl_pmcr0_el1&#34;&gt;SYS_APL_PMCR0_EL1
&lt;/h3&gt;&lt;p&gt;s3_1_c15_c0_0&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;[7:0] Counter enable for PMC #7-0&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;[10:8] Interrupt mode (0=off 1=PMI 2=AIC 3=HALT 4=FIQ)&lt;/li&gt;
&lt;li&gt;[11] PMI interrupt is active (write 0 to clear)&lt;/li&gt;
&lt;li&gt;[19:12] Enable PMI for PMC #7-0&lt;/li&gt;
&lt;li&gt;[20] Disable counting on a PMI&lt;/li&gt;
&lt;li&gt;[22] Block PMIs until after eret&lt;/li&gt;
&lt;li&gt;[23] Count global (not just core) L2C events&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[30] User-mode access to registers enable&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[33:32] Counter enable for PMC #9-8&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;[45:44] Enable PMI for PMC #9-8&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;sys_apl_pmcr1_el1&#34;&gt;SYS_APL_PMCR1_EL1
&lt;/h3&gt;&lt;p&gt;s3_1_c15_c1_0&lt;/p&gt;
&lt;p&gt;Controls which ELx modes count events&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[7:0] EL0 A32 enable PMC #0-7 (not implemented on modern chips)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[15:8] EL0 A64 enable PMC #0-7&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[23:16] EL1 A64 enable PMC #0-7&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;[31:24] EL3 A64 enable PMC #0-7 (not implemented except on old chips with EL3)&lt;/li&gt;
&lt;li&gt;[33:32] EL0 A32 enable PMC #9-8 (not implemented on modern chips)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[41:40] EL0 A64 enable PMC #9-8&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;[49:48] EL1 A64 enable PMC #9-8&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;[57:56] EL3 A64 enable PMC #9-8 (not implemented on modern chips)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;sys_apl_pmesr0_el1&#34;&gt;SYS_APL_PMESR0_EL1
&lt;/h3&gt;&lt;p&gt;s3_1_c15_c5_0&lt;/p&gt;
&lt;p&gt;Event selection register for PMC #2-5&lt;/p&gt;
&lt;h4 id=&#34;on-m1m2&#34;&gt;On M1/M2:
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;[7:0] event for PMC #2&lt;/li&gt;
&lt;li&gt;[15:8] event for PMC #3&lt;/li&gt;
&lt;li&gt;[23:16] event for PMC #4&lt;/li&gt;
&lt;li&gt;[31:24] event for PMC #5&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;on-m3m4&#34;&gt;On M3/M4:
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;[15:0] event for PMC #2&lt;/li&gt;
&lt;li&gt;[31:16] event for PMC #3&lt;/li&gt;
&lt;li&gt;[47:32] event for PMC #4&lt;/li&gt;
&lt;li&gt;[63:48] event for PMC #5&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;sys_apl_pmesr1_el1&#34;&gt;SYS_APL_PMESR1_EL1
&lt;/h3&gt;&lt;p&gt;s3_1_c15_c6_0&lt;/p&gt;
&lt;p&gt;Event selection register for PMC #6-9&lt;/p&gt;
&lt;h4 id=&#34;on-m1m2-1&#34;&gt;On M1/M2:
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;[7:0] event for PMC #6&lt;/li&gt;
&lt;li&gt;[15:8] event for PMC #7&lt;/li&gt;
&lt;li&gt;[23:16] event for PMC #8&lt;/li&gt;
&lt;li&gt;[31:24] event for PMC #9&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;on-m3m4-1&#34;&gt;On M3/M4:
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;[15:0] event for PMC #6&lt;/li&gt;
&lt;li&gt;[31:16] event for PMC #7&lt;/li&gt;
&lt;li&gt;[47:32] event for PMC #8&lt;/li&gt;
&lt;li&gt;[63:48] event for PMC #9&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;sys_apl_pmc0-9_el1&#34;&gt;SYS_APL_PMC0-9_EL1
&lt;/h3&gt;&lt;p&gt;Performance counter.&lt;/p&gt;
&lt;p&gt;On M1: 48 bits, bit 47 triggers PMI.
On M2/M3/M4: 64 bits, bit 63 triggers PMI.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PMC #0: fixed cpu cycle count if enabled&lt;/li&gt;
&lt;li&gt;PMC #1: fixed instruction count if enabled&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;According to my experiments, the main difference of PMUs on M3 and M4 is that their ESR regs are 64-bit, and each event takes 16 bits.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage
&lt;/h2&gt;&lt;p&gt;First, according to the register definitions, we need to set correct bit in &lt;code&gt;SYS_APL_PMCR0_EL1&lt;/code&gt; and &lt;code&gt;SYS_APL_PMCR1_EL1&lt;/code&gt; to enable PMC2-9 and allow EL0 and EL1 access to them, on a machine with a &lt;a class=&#34;link&#34; href=&#34;https://github.com/jprx/PacmanPatcher&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;patched kernel&lt;/a&gt;, we can write to the two regs in user mode.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mrs %0, s3_1_c15_c0_0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt;(SYS_APL_PMCR0));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mrs %0, s3_1_c15_c1_0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt;(SYS_APL_PMCR1));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SYS_APL_PMCR0 &lt;span style=&#34;color:#f92672&#34;&gt;|=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3ULL&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;;        &lt;span style=&#34;color:#75715e&#34;&gt;// enable PMC8-9
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;SYS_APL_PMCR0 &lt;span style=&#34;color:#f92672&#34;&gt;|=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;255ULL&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;       &lt;span style=&#34;color:#75715e&#34;&gt;// enable PMC0-7
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;SYS_APL_PMCR1 &lt;span style=&#34;color:#f92672&#34;&gt;|=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3ULL&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt;;        &lt;span style=&#34;color:#75715e&#34;&gt;// enable PMC8-9 EL0 access
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;SYS_APL_PMCR1 &lt;span style=&#34;color:#f92672&#34;&gt;|=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3ULL&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;48&lt;/span&gt;;        &lt;span style=&#34;color:#75715e&#34;&gt;// enable PMC8-9 EL1 access
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;SYS_APL_PMCR1 &lt;span style=&#34;color:#f92672&#34;&gt;|=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;255ULL&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;;       &lt;span style=&#34;color:#75715e&#34;&gt;// enable PMC0-7 EL0 access
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;SYS_APL_PMCR1 &lt;span style=&#34;color:#f92672&#34;&gt;|=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;255ULL&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;;      &lt;span style=&#34;color:#75715e&#34;&gt;// enable PMC0-7 EL1 access    
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;msr s3_1_c15_c0_0, %0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;(SYS_APL_PMCR0));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;msr s3_1_c15_c1_0, %0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;(SYS_APL_PMCR1));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It’s worth noting that &lt;code&gt;SYS_APL_PMCR0_EL1&lt;/code&gt; may be repeatedly overwritten by a kernel process, and any modifications to that register typically won&amp;rsquo;t persist longer than ~100 µs. Thus, we can&amp;rsquo;t enable the PMU event counter for longer than that time unless we patch the kernel again with a modified patcher, which is theoretically practical.&lt;/p&gt;
&lt;p&gt;Then we need to set the event ID to the PMESR regs (SYS_APL_PMESR0_EL1, SYS_APL_PMESR1_EL1). Notice that the bit widths are different on M1/M2 and M3/M4, the former is 8bit for each event, the latter is 16bit.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mrs %0, s3_1_c15_c5_0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt;(SYS_APL_PMESR0));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mrs %0, s3_1_c15_c6_0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt;(SYS_APL_PMESR1));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SYS_APL_PMESR0 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1443ULL&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;      &lt;span style=&#34;color:#75715e&#34;&gt;// L1D_CACHE_MISS_LD on PMC2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;SYS_APL_PMESR1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1441ULL&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;      &lt;span style=&#34;color:#75715e&#34;&gt;// L1D_TLB_MISS on PMC6
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;msr s3_1_c15_c5_0, %0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;(SYS_APL_PMESR0));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;msr s3_1_c15_c6_0, %0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;(SYS_APL_PMESR1));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After setting the PMCR and PMESR regs, we can just read PMC2-9 (depending on the bits you set in PMESR) to get the counting of the event of interest.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mrs x9, S3_2_c15_c2_0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:::&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;x9&amp;#34;&lt;/span&gt;);     &lt;span style=&#34;color:#75715e&#34;&gt;// read PMC2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mrs x10, s3_2_c15_c6_0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n\t&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:::&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;x10&amp;#34;&lt;/span&gt;);   &lt;span style=&#34;color:#75715e&#34;&gt;// read PMC6
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, after you&amp;rsquo;ve got all the counter data, read SYS_APL_PMCR0_EL1 back and check the bits you set haven&amp;rsquo;t been overwritten by the kernel yet. This ensures the PMU event counter data you&amp;rsquo;ve read is still valid.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;asm&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volatile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mrs %0, s3_1_c15_c0_0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;=r&amp;#34;&lt;/span&gt;(SYS_APL_PMCR0));    &lt;span style=&#34;color:#75715e&#34;&gt;// confirm PMCR0 changed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
        </item>
        <item>
        <title>家庭照片管理——用Docker部署Photoprism</title>
        <link>https://blog.clf3.org/post/photoprism/</link>
        <pubDate>Sat, 20 Apr 2024 00:53:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/photoprism/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/photoprism/photoprism01.webp" alt="Featured image of post 家庭照片管理——用Docker部署Photoprism" /&gt;&lt;p&gt;前几天（其实已经是上个学期了）Yoghurt Lee给我看了一个照片管理的开源项目：&lt;a class=&#34;link&#34; href=&#34;https://github.com/photoprism/photoprism&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Photoprism&lt;/a&gt;。突然想起我家的各种照片，从零几年的卡片机到近几年手机拍的都有。虽然我爸和我已经在包括电脑硬盘、ownCloud网盘、移动硬盘和百度网盘在内的多种存储介质上备份了我家的照片，但这些照片仍然缺乏有效的整理，查看起来也不那么方便。看到有Photoprism这种Self-hosted的照片管理，支持按时间分类、按识别结果自动分类、照片地图、人脸识别等许多功能，我一颗折腾的心又一次按捺不住了，于是开始在我的服务器上部署。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/photoprism/photoprism01.webp&#34;
	width=&#34;3840&#34;
	height=&#34;1861&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;206&#34;
		data-flex-basis=&#34;495px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;我所使用的是一台Ubuntu 22.04 LTS系统的虚拟机，考虑到Photoprism对计算有一定要求，我分配了16个vCPU和4G内存，硬盘是1.2T。为了方便之后可能的迁移，我决定使用Docker，这样以后需要迁移的时候只需要把数据文件夹复制过去，再重新Docker compose就可以了。我们首先安装Docker：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Add Docker&amp;#39;s official GPG key:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get install ca-certificates curl
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo install -m &lt;span style=&#34;color:#ae81ff&#34;&gt;0755&lt;/span&gt; -d /etc/apt/keyrings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo chmod a+r /etc/apt/keyrings/docker.asc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Add the repository to Apt sources:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deb [arch=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;dpkg --print-architecture&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;  &lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;. /etc/os-release &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$VERSION_CODENAME&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; stable&amp;#34;&lt;/span&gt; | &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable docker.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面代码的最后一行是启动Docker服务，这样你的容器才能自动启动。如果安装太慢，可以换用清华源。安装好之后，新建一个目录，配好docker-compose.yml文件。我是按照官网给的示例文件配的，只把restart: unless-stopped一行取消了注释（这样可以保证容器开机自动启动）。&lt;/p&gt;
&lt;p&gt;随后我们便可以启动Docker：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo docker compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一次compose up会拉取Docker镜像文件，这一步如果过慢，可以换用南大的Docker Hub源，方法是打开或创建/etc/docker/daemon.json，在其中添加以下内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;registry-mirrors&amp;#34;&lt;/span&gt;:[
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://docker.nju.edu.cn/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后重新compose up，速度就会有明显改善。启动Docker后，由于配置文件里Photoprism使用的默认端口是2342，这时curl localhost:2342，已经可以获取到一些内容了。接下来我们只需要在服务器软件里配置转发到对应端口就可以实现标准端口的公网访问了，如果你和我一样，使用的是Apache 2，而且打算启用HTTPS（SSL证书申请可以看Let’s encrypt的教程），那可以参考下面的配置文件：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
        ServerName your.domain
        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI}
&amp;lt;/VirtualHost&amp;gt;
 
&amp;lt;VirtualHost *:443&amp;gt;
        ServerName your.domain
        SSLEngine on
        SSLCertificateFile your/certificate
        SSLCertificateKeyFile your/privkey
        RewriteEngine on
        RewriteCond %{HTTP:Upgrade} websocket [NC]
        RewriteCond %{HTTP:Connection} upgrade [NC]
        RewriteRule ^/?(.*) &amp;#34;ws://localhost:2342/$1&amp;#34; [P,L]
        ProxyRequests off
        ProxyPass / http://localhost:2342/
        ProxyPassReverse / http://localhost:2342/
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注意，中间几行的Rewrite是对websocket的转发，Photoprism的一些功能需要websocket。如果websocket没有被正确配置，Photoprism网页的侧栏会出现相关提示。如果你使用的是nginx，那配置也是类似的：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name your.domain;
    ssl_certificate your/certificate;
    ssl_certificate_key your/privkey;
    client_max_body_size 50G;
 
    location / {
      proxy_pass http://localhost:2342/;
      proxy_set_header Host $http_host;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection upgrade;
      proxy_set_header Accept-Encoding gzip;
    }
}
server {
    listen 80;
    listen [::]:80;
    server_name your.domain;
    rewrite ^(.*)$ https://${server_name}$1 permanent;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;接着我们重启Apache，再在DNS服务商那添加一条域名解析记录，我们就可以访问到Photoprism的页面了：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/photoprism/photoprism02.webp&#34;
	width=&#34;3819&#34;
	height=&#34;1864&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;204&#34;
		data-flex-basis=&#34;491px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;按照我们在docker配置文件里写好的账号密码，我们可以登录Photoprism。Photoprism支持从网页上传图片，也可以导入存放在本地import目录的图片文件。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/photoprism/photoprism03.webp&#34;
	width=&#34;3831&#34;
	height=&#34;1858&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;206&#34;
		data-flex-basis=&#34;494px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;Photoprism会对导入的图片进行重新编目，这些图片文件会被求算哈希并去重，之后所有的图片会被统一命名，存在original文件夹中。同时Photoprism会读取照片的EXIF地理位置信息，并根据拍摄位置把照片显示在地图上，当你放缩地图的时候，不同时间、地点的照片还会自动合并和展开，这个功能还是很惊艳的：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/photoprism/photoprism04.webp&#34;
	width=&#34;3820&#34;
	height=&#34;1863&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;205&#34;
		data-flex-basis=&#34;492px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;除此之外，Photoprism还有人脸识别和场景识别功能，能识别出照片里的人脸和照片所属的场景（不过准确度只能说差强人意），并根据人物或或场景对图片进行归类。当然，作为一个相册软件，Photoprism也支持手动创建相册，收藏图片。&lt;/p&gt;
&lt;p&gt;Photoprism的照片预览同样很快（似乎是通过预先生成thumbnail图的方式实现的），在浏览大量图片的时候也能非常流畅。但是如果你的图片很多，那你点进其中一个查看原图的时间还是比较长的。（但是如果在查看原图界面连续浏览后面的图片，加载速度也很快，只有刚点进去的那一次比较慢。）&lt;/p&gt;
&lt;p&gt;此外，值得一提的是，Photoprism对系统配置的要求还是比较高的（似乎是因为需要本地跑AI推理来实现人脸识别和场景识别），如果一次上传上千张图片，那上传后的索引时间也是挺长的。我给我的这个虚拟机分配的4G内存最多只占用2G左右，但索引的过程中16个CPU核心都会被占满。（我已经能想象到我那台E5服务器的咆哮声了。）如果使用NAS运行这些东西，可能会有点费劲。&lt;/p&gt;
&lt;p&gt;总的来说Photoprism的效果还是很令人满意的，接下来一段时间我都会用它管理我们家的照片。最后附上经典人工智障图：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/photoprism/photoprism05.webp&#34;
	width=&#34;846&#34;
	height=&#34;391&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;216&#34;
		data-flex-basis=&#34;519px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>用Docker部署我的世界服务器实现多人联机</title>
        <link>https://blog.clf3.org/post/docker-mc/</link>
        <pubDate>Mon, 08 Apr 2024 11:17:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/docker-mc/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/docker-mc/mc01.webp" alt="Featured image of post 用Docker部署我的世界服务器实现多人联机" /&gt;&lt;p&gt;在刚开始折腾服务器时我就尝试开过我的世界服务器，最开始是直接简单粗暴地在Windows系统里运行，后来搬到我的Linux虚拟机上，开一个TMUX运行。但一直不能实现服务的自动启动，无论是Windows的开机启动任务还是Ubuntu的crontab似乎都不能让MC服务器正确的运行。&lt;/p&gt;
&lt;p&gt;于是我决定用Docker部署一下我的Minecraft服务器，这样就可以方便地自动启动和重启服务器。我的服务器是1.19.4版本，使用Forge，添加了暮色森林模组，首先也是从Minecraft Docker的&lt;a class=&#34;link&#34; href=&#34;https://docker-minecraft-server.readthedocs.io/en/latest/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Document&lt;/a&gt;上找到一个compose.yaml的模板，然后按照我自己的要求进行了一些修改：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3.8&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;mc&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;itzg/minecraft-server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;tty&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;stdin_open&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;25565:25565&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;EULA&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TRUE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;VERSION&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.19.4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;TYPE&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;FORGE&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# http_proxy: &amp;#34;http://192.168.3.2:10811&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# https_proxy: &amp;#34;http://192.168.3.2:10811&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;INIT_MEMORY&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1G&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;MAX_MEMORY&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;4G&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;DIFFICULTY&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;hard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;OP_PERMISSION_LEVEL&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;SPAWN_PROTECTION&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ALLOW_FLIGHT&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ONLINE_MODE&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# attach the relative directory &amp;#39;data&amp;#39; to the container&amp;#39;s /data path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./data:/data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;unless-stopped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里指定了VERSION和TYPE环境变量，设置代理是为了更快地下载Forge，下载完可以注释掉。其他一些服务器参数都可以通过环境变量的方式在这里设定，具体参阅Minecraft Docker的文档。最后一行表示除非手动停止，否则每次开机都重新启动这个Container。要实现这一点，我们还要保证Docker的守护进程能开机自启动：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable docker.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;准备好后，我们可以：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo docker compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果下载过慢，可以换用南大Docker Hub源，方法是打开或创建/etc/docker/daemon.json，在其中添加以下内容&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;registry-mirrors&amp;#34;&lt;/span&gt;:[
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://docker.nju.edu.cn/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你希望在Docker上开一个新的服务器，那么步骤到这里就结束了。但由于我要保留原先的地图和添加模组，需要在启动后docker compose down关闭这个Docker，再把world文件夹和mods文件夹替换掉，之后重启Docker就能正常运行了。&lt;/p&gt;
&lt;p&gt;由于我的服务器有公网IP，所以只需要将外网25565端口映射到这台虚拟机上的25565端口就可以了。如果你没有公网IP，可能还需要内网穿透才能让局域网之外的玩家也能访问。配置好网络后，在游戏里输入对应的IP或域名（如果没有使用25565端口，还需指定端口号），就可以看到我们的服务器了：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/docker-mc/mc02.webp&#34;
	width=&#34;3840&#34;
	height=&#34;2160&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Docker初探——用Docker部署Homepage</title>
        <link>https://blog.clf3.org/post/docker-initial/</link>
        <pubDate>Mon, 08 Apr 2024 00:48:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/docker-initial/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/docker-initial/docker.webp" alt="Featured image of post Docker初探——用Docker部署Homepage" /&gt;&lt;p&gt;前段时间看到一个很有意思的项目，&lt;a class=&#34;link&#34; href=&#34;https://github.com/gethomepage/homepage&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Homepage&lt;/a&gt;。就是一个很好看的静态导航页，想到我那用HTML手搓的（甚至没写CSS）简陋到用“简陋”一词都不足以形容的导航页，我顿时心动了。&lt;/p&gt;
&lt;p&gt;我原本以为既然Document里声称这个项目是纯静态的网页，那我是不是在本地生成好静态页面之后扔到我某个服务器的www目录，再随便写点配置就行了呢？但我鼓捣了半天才发现并非如此。首先这个项目并不希望你这样做，比如他的npm run build默认不会生成dist文件夹；此外这个网页也并不是完全静态的，它涉及一些系统参数的获取（CPU占用、内存占用等）以及天气API，如果非要生成一个静态页面，那这些API也不能正常工作。&lt;/p&gt;
&lt;p&gt;而官方最推荐的部署方式就是使用Docker，这下从没用过Docker的我也打算尝试一下了，顺便把我的Minecraft服务器也搬到Docker上，这样就可以完全变成一个服务，方便地自启动和重启了（每次重启机器都去开TMUX手动启动实在是太不优雅了）。&lt;/p&gt;
&lt;p&gt;简单了解了一下，Docker其实就是一个介于虚拟机和直接多开程序之间的一种方案，它的资源占用要比开虚拟机更少，同时也能给不同的服务提供独立的环境，避免互相干扰。&lt;/p&gt;
&lt;p&gt;看了一下Docker的Manual以及一些教程，我决定使用docker compose，这个按照我的理解就是把一个Docker的配置写进一个配置文件里，这样每次启动这个Docker就只需要读这个配置文件就行了，这样更容易部署成一个服务。&lt;/p&gt;
&lt;p&gt;首先创建一个新文件夹，在里面创建一个名叫compose.yaml的文件，这就是这个Docker的配置文件了。按照Homepage的教程，这个文件应该有如下内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3.3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;homepage&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ghcr.io/gethomepage/homepage:latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;homepage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;3000&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;3000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;/path/to/config:/app/config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;unless-stopped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的image代表所使用的Docker镜像；ports代表把外部的端口（左侧）映射到Docker内部的某个端口；volumes则是代表将外部的目录（左侧）挂载到Docker内部的某个位置。restart一项是我额外添加的，为了让这个容器在开机时能自启动。&lt;/p&gt;
&lt;p&gt;写完这个compose.yaml，我们就可以把自己写好的Homepage配置文件放到上面指定的目录下，待会运行Docker的时候Docker里面的Homepage服务就可以根据这个配置文件渲染对应的页面。&lt;/p&gt;
&lt;p&gt;接下来在终端输入：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个命令就会根据你在compose.yaml里指定的配置为你生成一个Docker并运行，这时我们curl localhost:3000，可以看到页面源代码，说明配置成功了。再在终端输入：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable docker.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样docker服务就会被启用，如果你在compose.yaml正确配置了restart参数，那这个容器就能开机自启动了。&lt;/p&gt;
&lt;p&gt;接下来就是在你的nginx或者其他服务器软件里设置一个端口转发，让你的页面能正确显示在公网，我的配置如下，供参考：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name nvg.clf3.org;
    ssl_certificate /certificate/path;
    ssl_certificate_key /privkey/path;
    client_max_body_size 50G;
    location / {
      proxy_pass http://localhost:3000/;
      proxy_set_header Host $http_host;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection upgrade;
      proxy_set_header Accept-Encoding gzip;
    }
}
server {
    listen 80;
    listen [::]:80;
    server_name nvg.clf3.org;
    rewrite ^(.*)$ https://${server_name}$1 permanent;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最后配置好的效果&lt;a class=&#34;link&#34; href=&#34;https://nvg.clf3.org&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;在这里&lt;/a&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/docker-initial/docker.webp&#34;
	width=&#34;3840&#34;
	height=&#34;2160&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;感觉用Docker部署这种配置好就不用怎么动的服务还是很适合的，现在有点想把我的所有服务都docker化了。主要是想配置的服务越来越多，但每次都开一个新的虚拟机，即使是64G内存也有点捉襟见肘，如果都放到一个Linux机器上，又担心环境冲突。等到我又想部署新项目的时候，可能就考虑把之前的Wordpress、Gitea之类的给Docker化了。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>如何制作属于自己的Grub主题</title>
        <link>https://blog.clf3.org/post/grub-theme-tutorial/</link>
        <pubDate>Wed, 03 Jan 2024 01:55:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/grub-theme-tutorial/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/grub-theme-tutorial/grub03.webp" alt="Featured image of post 如何制作属于自己的Grub主题" /&gt;&lt;p&gt;最近给自己的笔记本电脑换了块硬盘，想着既然要从头开始装系统那不如就整一个Windows+Linux双系统。但装完双系统后，每次启动都会进入Grub的系统选择界面。而Grub的默认界面又极其简陋，对高分屏的适配也并不好。因此我萌生了给Grub更换一个主题的想法。&lt;/p&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.gnome-look.org/browse?cat=109&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;这个网站&lt;/a&gt;上有很多Grub主题，但我找了一圈我也没看到有太合适的。 这时我就想自己做一个Grub主题了，作为一个忠实的锦依卫，这个主题肯定也要包含天依的元素了~&lt;/p&gt;
&lt;p&gt;首先我想先了解一下一个Grub主题都应该包括一些什么，于是我在上面的网站上下载了一个星铁的Grub主题看了一下，这个主题包含了下面这些文件：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/grub-theme-tutorial/grub01.webp&#34;
	width=&#34;1121&#34;
	height=&#34;565&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;198&#34;
		data-flex-basis=&#34;476px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;经过一番研究和查阅&lt;a class=&#34;link&#34; href=&#34;https://www.gnu.org/software/grub/manual/grub/html_node/Theme-file-format.html#Theme-file-format&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Grub官方文档&lt;/a&gt;，我大致弄明白了这些东西都是干什么的。icons文件夹放着各个系统的图标，是用在每个系统的选项前面的；background.png是背景图片；selected_*.png是一些贴图，作用后面会讲；最核心的是theme.txt，这个文件包含了这个主题的配置信息，在我下载的这个主题里，theme.txt文件长这样：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;title-text: &amp;#34;&amp;#34;
desktop-image: &amp;#34;background.png&amp;#34;
terminal-left: &amp;#34;0&amp;#34;
terminal-top: &amp;#34;0&amp;#34;
terminal-border: &amp;#34;0&amp;#34;
terminal-width: &amp;#34;100%&amp;#34;
terminal-height: &amp;#34;100%&amp;#34;
 
+ boot_menu {
  left = 120
  top = 47%
  width = 472
  height = 35%
  item_color = &amp;#34;#cccccc&amp;#34;
  selected_item_color = &amp;#34;#ffffff&amp;#34;
  icon_width = 36
  icon_height = 36
  item_icon_space = 20
  item_height = 40
  item_padding = 2
  item_spacing = 40
  selected_item_pixmap_style = &amp;#34;select_*.png&amp;#34;
}
 
+ label {
  left = 120
  top = 83%
  align = &amp;#34;center&amp;#34;
  id = &amp;#34;__timeout__&amp;#34;
  text = &amp;#34;Selected OS will start in %d seconds&amp;#34;
  color = &amp;#34;#cccccc&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最开始的一段是一些全局属性，title-text是标题，显示在上方中央的位置；desktop-image指定了背景图片，terminal-left和terminal-top则指定了Grub Terminal的左上角的位置，terminal-width和terminal-height就是Terminal的宽度和高度。这些宽度、高度和位置的指定都支持使用像素或者百分比或者两者混合，例如&amp;quot;12%+100&amp;quot;。下文提到的宽度、高度和位置也同理。&lt;/p&gt;
&lt;p&gt;下面的boot_menu和label是两个组件(component)，boot_menu就是给出选项的启动菜单，而label代表你希望自定义显示的一段话。每个组件有自己的属性，其中left, top, width, height含义和全局的类似，就是表示左上角的位置以及组件本身的长宽。item_color和selected_item_color顾名思义，就是每一项的文字默认颜色以及被选中时的颜色。下面一些项指定了图标的长宽，项目文字和图标的距离，项目之间的距离等等，具体可以查阅官方文档，在此不再赘述。而selected_item_pixmap_style是一个非常有意思的东西，它相当于通过9张小图片指定了一个item的四角、四边以及内部应该用什么样的贴图，我们需要给它9张后缀分别为c, e, n, s, w, ne, nw, se, ew的小图片，Grub就会自己把它们拼成一个完整的背景用在这个item上，selected_item_pixmap_style则表明仅有被选中的item适用这个贴图。&lt;/p&gt;
&lt;p&gt;label组件的各种东西是类似的，需要注意的是id设为&amp;quot;&lt;strong&gt;timeout&lt;/strong&gt;&amp;ldquo;就可以使用%d在文字中代表剩余秒数。&lt;/p&gt;
&lt;p&gt;知道了这些之后我们就可以开始创建自己的主题了,首先我们需要准备一张背景图片，从我的天依图库翻了翻，最后决定还是这张：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/grub-theme-tutorial/grub02.webp&#34;
	width=&#34;967&#34;
	height=&#34;1500&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;64&#34;
		data-flex-basis=&#34;154px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;在PS里简单截取拼接之后我们就得到了下面的图片，由于Grub的字体比较有限，而且大小也很难调整，所以我选择将标题做到背景图片里：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/grub-theme-tutorial/grub03.webp&#34;
	width=&#34;2520&#34;
	height=&#34;1680&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;150&#34;
		data-flex-basis=&#34;360px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;这就是背景图了，为了让选中项有一些特殊效果，我需要自己制作selected_item_pixmap_style使用的那九张贴图，其实也很简单，在PS里创建一张5*5像素的小图片，然后填色就行了。我用的是#66ccff的天依蓝，加了不同的透明度，边框是白色。这是右上角的图片(select_ne.png)在PS里的效果：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/grub-theme-tutorial/grub04.webp&#34;
	width=&#34;193&#34;
	height=&#34;197&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;97&#34;
		data-flex-basis=&#34;235px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;之后只需要调整一下各个元素的位置和间距，然后就大功告成了！效果的话可以看下面这张图（主要是实在想不出如何把Grub的界面截屏，只有拍屏了）：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/grub-theme-tutorial/grub05.webp&#34;
	width=&#34;4096&#34;
	height=&#34;3072&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;320px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;完整的配置文件我开源在了&lt;a class=&#34;link&#34; href=&#34;https://github.com/ClF3/tianyi-grub-theme&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Github&lt;/a&gt;上，大家可以自行查看。下面再来讲讲怎么使用Grub主题，这里以Ubuntu为例，其他发行版可能在文件路径和命令上存在一些差异。首先创建主题目录，然后从我的Github或者Gitea上下载主题：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /boot/grub/themes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone git@github.com:ClF3/tianyi-grub-theme.git /boot/grub/themes/tianyi    &lt;span style=&#34;color:#75715e&#34;&gt;# 使用github，可能需要科学上网&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://git.clf3.org/tianyi/tianyi-grub-theme.git /boot/grub/themes/tianyi    &lt;span style=&#34;color:#75715e&#34;&gt;# 使用gitea，可能不稳定&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后打开/etc/default/grub，在这个配置文件中添加下面的内容，用来指定Grub主题文件的位置：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;GRUB_THEME=&amp;#34;/boot/grub/themes/tianyi/Tianyi/theme.txt&amp;#34;
# 对于1080p屏幕
GRUB_THEME=&amp;#34;/boot/grub/themes/tianyi/Tianyi_2k/theme.txt&amp;#34;
# 对于2520*1680屏幕
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在配置文件里指定好新主题的位置后，我们运行下面的命令重新编译Grub：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo update-grub
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后重启电脑就可以看到新的Grub主题了。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>新年快乐</title>
        <link>https://blog.clf3.org/post/happy-new-year/</link>
        <pubDate>Mon, 01 Jan 2024 00:10:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/happy-new-year/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/happy-new-year/new-year.webp" alt="Featured image of post 新年快乐" /&gt;&lt;p&gt;祝看到这条博客的所有人新年快乐！（虽然可能不会有什么人看）&lt;/p&gt;
</description>
        </item>
        <item>
        <title>我的服务器近况介绍</title>
        <link>https://blog.clf3.org/post/whats-on-my-server/</link>
        <pubDate>Sat, 23 Dec 2023 09:38:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/whats-on-my-server/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/whats-on-my-server/server01.webp" alt="Featured image of post 我的服务器近况介绍" /&gt;&lt;p&gt;介绍一下我的服务器当前的状况：服务器硬件是E5洋垃圾，详细配置参见&lt;a class=&#34;link&#34; href=&#34;https://blog.clf3.org/post/server-01&#34; &gt;在家折腾服务器的经过——系统搭建和测试跑分&lt;/a&gt;；系统是Windows Server 2022 Standard，使用Hyper-V创建了四台Linux虚拟机，分别运行本博客、网盘、Git和VS Code Server。&lt;/p&gt;
&lt;p&gt;此前我的各种服务主要运行在Windows Server系统内，主要是比较习惯图形界面。但熟悉了命令行之后我发现很多服务在Linux服务器上配置要简单和省事许多，而且Linux系统的性能占用也较少，我的64GB内存和12核CPU可以轻松实现多开虚拟机，将不同的服务隔离开来。&lt;/p&gt;
&lt;p&gt;下面分别介绍一下我目前各种东西的解决方案，首先是域名注册。起初我选择的是Gandi，但后来被它堪称黑心的价格劝退了。现在使用的是Dynadot，感觉还很不错，一个.com域名一年只需要$10多一点，DNSSEC什么的也是免费的，同时附带一个免费邮箱。我的个人邮箱clf3@clf3.org和天依邮箱tianyi@tianyi.moe现在就都是托管在Dynadot上的。&lt;/p&gt;
&lt;p&gt;然后是DNS和CDN，这方面我选择的是Cloudflare，当然目前我主要只使用了它的DNS解析和页面规则（设置301跳转）。因为Cloudflare的CDN在中国大陆堪称减速器，许多运营商都会把发往Cloudflare的请求绕到美国的节点，延迟丢包都巨高。这里点名表扬CERNET，它可以直连CF的香港节点，延迟30ms左右（点名批评中国联通，实在想不明白绕这么远的路对它自己有什么好处）。&lt;/p&gt;
&lt;p&gt;再说一下DDNS。由于我使用的是家庭宽带，公网IP会时常变动（具体是大约每七天运营商断线重拨一次），因此需要一个DDNS的脚本来实时改变域名（主要是clf3.org及其子域名）的解析。此前我使用的是自己写的一个Python脚本，但功能不是很完善，且配置起来比较麻烦。恰好我的一个室友用Rust写了一个&lt;a class=&#34;link&#34; href=&#34;https://github.com/un-lock-able/cloudflare-ddns-rust&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;使用Cloudflare API进行DDNS的脚本&lt;/a&gt;，经过多次改进后现在我用起来效果还不错，修改配置也很方便。&lt;/p&gt;
&lt;p&gt;网络方面，由于家庭宽带的IPv4地址都会封掉80、443端口，只有v6地址的80、443不会被封。为了实现v4、v6双栈访问，我使用了一台日本东京的VPS进行反代，将v4的HTTPS流量通过v6转发到我家里的服务器，速度和延迟都也还可以，我们家到日本东京这台VPS延迟只有大约80ms。&lt;/p&gt;
&lt;p&gt;然后是TLS证书，这里我选择的是Let’s encrypt，主要是因为免费。而且Let’s encrypt官方有一个用来自动更新证书的脚本Certbot，使用起来还比较方便。目前我在我所有的服务器上均使用*.clf3.org的通配符证书，有效期三个月。&lt;/p&gt;
&lt;p&gt;博客方面我使用的就是你们现在看到的WordPress。我对博客的要求本身也不是很高，有一个可以写一些文字的地方也就很够用了。WP的好处在于操作比较傻瓜式，模板和插件也相对较多。但缺点就是基本上要跟着模板走，有些东西没法自定义，而且对代码的支持也不太好。&lt;/p&gt;
&lt;p&gt;网盘我使用的是ownCloud社区版，我的ownCloud运行在一个单独的虚拟机中，这个虚拟机独占一组RAID1阵列，磁盘空间为1200GB。ownCloud的界面还算简洁美观，功能也比较全，webDAV、同步软件和手机APP都有。但是同步软件和手机APP使用体验极差，似乎它们的同步机制存在某些问题，经常有文件被上传两次，甚至发生冲突无法继续上传。不过网页端和webDAV目前使用都还比较正常。&lt;/p&gt;
&lt;p&gt;Git服务我使用的是Gitea，体验还是不错的，Github能实现的功能它也基本都能实现。美中不足的有两点：一是无法使用SSH，只能用HTTPS。因为正如上文提到的，我的所有网站的v4访问都是通过转发实现的，而SSH没有主机名，无法实现按域名的转发。二是不能实现可视化查看分支，Github的insight项中有一个network功能，可以可视化地查看不同分支之间的关系，但Gitea目前没有这个功能。&lt;/p&gt;
&lt;p&gt;此外，为了实现随时随地写代码，我在服务器上还部署了一个Code Server，也就是一个网页版的VS Code。这样无论在哪里，使用什么设备，只要能联网，就能使用服务器上的环境进行开发。这个项目是Github上的一个开源项目，链接在&lt;a class=&#34;link&#34; href=&#34;https://github.com/coder/code-server&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;接下来我打算学习Vue，从头开始自己写一个使用Vue前端+Django后端的网站。这个网站主要会分享一些中V相关的资源，将使用tianyi.moe这个域名（可能还有tianyiblue.com）。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>在家折腾服务器的经过——https证书申请和配置</title>
        <link>https://blog.clf3.org/post/server-04/</link>
        <pubDate>Thu, 07 Sep 2023 02:56:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/server-04/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/server-04/server19.webp" alt="Featured image of post 在家折腾服务器的经过——https证书申请和配置" /&gt;&lt;p&gt;完善了Alist服务之后，我决定给它用上https。但是Alist自己的服务应该不支持直接做https，所以在查阅一番之后我决定用Nginx反代再在nginx上用上https。&lt;/p&gt;
&lt;p&gt;Nginx配置文件的结构是http内可以有多个server，相当于多个虚拟的host，每个server又可以有多个的location，我先配置了一个server，让他listen本地的80端口。至于具体如何反代到Alist的5244端口，在Alist官方文档专门列出了配置location的示例代码，我只在示例代码上稍作修改就可以运行了，我使用的location代码如下：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;location / {
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header Host $http_host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Range $http_range;
  proxy_set_header If-Range $http_if_range;
  proxy_redirect off;
  proxy_pass http://127.0.0.1:5244;
  # the max size of file to upload
  client_max_body_size 50000m;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这样配置完成后，我们输入对应IP就可以直接访问我的Alist。但这只是完成了第一步，转发后依然采用的是http服务，下面我就要申请SSL证书，并建立起https的网络服务。&lt;/p&gt;
&lt;p&gt;提供证书的是Let’ s encrypt，别问为什么，问就是免费。Let’ s encrypt的certbot还可以让我自动获取证书并用到我的服务器上，我觉得这一点也很好。&lt;/p&gt;
&lt;p&gt;我采用的认证方式是DNS认证，也就是创建并删除指定的DNS记录以证明你对整个域名的所有权，这样做的好处主要是可以获得通配符证书，也就是对我的所有子域名都有效的证书。&lt;/p&gt;
&lt;p&gt;Certbot官网有针对不同系统和应用的配置教程，我选择了Nginx+Ubuntu 20的项（其实我是Ubuntu 22，但上面没有）。先用snap安装好Certbot，再安装Certbot的Cloudflare插件，这个插件就可以帮助我实现自动更新DNS从而自动获取新的证书。&lt;/p&gt;
&lt;p&gt;之后，按照Cloudflare插件的教程，我将我的Cloudflare API key放到了一个文件里供插件调用，接下来就只需要仿照示例的格式尝试获取一次证书：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;certbot &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --dns-cloudflare &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;  -d clf3.org -i nginx
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后Certbot会自动获取证书，保存到本地，并改写nginx配置文件使其支持https。观察配置文件发现它自动把我server的listen端口改到443，配置了一些SSL之类的选项，又把80端口重定向到https的443端口。之后我们用https访问服务器IP，就能看到证书，当然，由于用的是IP，此时会提示证书无效，我们只需在路由器里添加一个端口映射就可以通过我的公网域名访问到我的Alist了。&lt;/p&gt;
&lt;p&gt;但是我又发现了一个问题，我的服务器只开启了https，但如果仅输入域名和端口号，浏览器默认尝试以http的方式访问，因此只能看到一个错误页面。其实Certbot也考虑到了这一点，所以把服务器的80重定向到了443。但由于我是在路由器上开的端口映射，只能把公网IP的特定端口转到443。这也就导致了浏览器尝试用http访问时，这个http请求也直接被转发到服务器的443端口，而引发错误码497，所以我们只需要把错误码497的错误页面直接改成对应的https的网站页面就可以了：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;error_page 497 https://$http_host$request_uri
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后执行nginx -s reload更新Nginx配置。现在我们就可以在浏览器输入我的域名加上端口，之后就可以直接跳转到对应的https页面了。&lt;/p&gt;
&lt;p&gt;我们查看一下证书，也没有任何问题：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-04/server19.webp&#34;
	width=&#34;1841&#34;
	height=&#34;1290&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;142&#34;
		data-flex-basis=&#34;342px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;这样一来，我的Alist就使用上了https服务，我与服务器之间的连接也就是完全加密的了。&lt;/p&gt;
&lt;p&gt;目前为止我的服务器的安全措施虽然不是非常完善，但至少不是一点没有。除了Alist服务使用直接开放端口的方式以外，其他网页服务我都使用了Cloudflare的CDN，从我这里到Cloudflare走的是加密的Tunnel，从Cloudflare再到用户走的是用Cloudflare的证书签名的https，也实现了全程的数据加密。&lt;/p&gt;
&lt;p&gt;至于SSH和RDP，我暂时的做法是不用默认端口，改成一个高位的随机端口，这样被扫描到的概率也会小一点，同时设置强密码，正常情况下要靠爆破是很难侵入我的系统的。&lt;/p&gt;
&lt;p&gt;目前我在路由器上设置转发的只有Alist端口、MC服务器的两个端口、SSH端口和RDP端口，除此之外一切入站流量都应该是被拒绝的。&lt;/p&gt;
&lt;p&gt;当然安全方面我很可能也有没有考虑到的方面，以后想到了再加强吧。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>在家折腾服务器的经过——Gitea和Alist部署</title>
        <link>https://blog.clf3.org/post/server-03/</link>
        <pubDate>Wed, 06 Sep 2023 18:18:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/server-03/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/server-03/server15.webp" alt="Featured image of post 在家折腾服务器的经过——Gitea和Alist部署" /&gt;&lt;p&gt;本着物尽其用的原则，我决定在我的服务器上添加更多的服务，首先，我想搭建一个属于自己的Git服务器。这里我选择了Gitea，因为它安装非常简单，功能也比较全面。&lt;/p&gt;
&lt;p&gt;Gitea是支持Windows端的，所以我打算直接在我的Windows Server机器上搞。首先为Gitea创建一个数据库，因为之前已经装好了WAMP的集成环境，所以我们只需要进入MySQL的管理后台，新建一个数据库就行了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-03/server14.webp&#34;
	width=&#34;839&#34;
	height=&#34;138&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;607&#34;
		data-flex-basis=&#34;1459px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;在正式开始安装之前，我们首先要在服务器上安装Git，安装后也不需要进一步的操作，只要有Git的环境就可以了。&lt;/p&gt;
&lt;p&gt;接下来我们把下载下来的exe文件放到一个空文件夹里，然后运行，接下来会弹出一个cmd窗口，提示已经在localhost:3000开启了服务器，接下来就是访问这个网页，按照相应的提示完成配置就行了。然后在Cloudflare Dashboard上添加一条转发到localhost:3000的记录就可以了，整个过程和Wordpress的安装很类似。安装好的效果就是下面这个网页：&lt;/p&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://git.clf3.org/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://git.clf3.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-03/server15.webp&#34;
	width=&#34;3831&#34;
	height=&#34;1834&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;208&#34;
		data-flex-basis=&#34;501px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;接下来我打算整一个个人网盘，经过一番比较我选择了Alist，因为在各家的免费方案中，Alist提供的功能算是其中比较丰富的了，而且安装同样很简便。但是Alist没有Windows版，所以我只能在我的Linux虚拟机上搭建Alist服务了。&lt;/p&gt;
&lt;p&gt;Alist官方提供了一键安装脚本，可以直接完成所有的安装和配置，运行一键安装脚本后，程序本体默认在/opt/alist目录，而服务器默认开放在localhost:5244端口，一开始打开时未挂载任何文件，因此目录是空白的，在管理-存储界面可以添加存储。理论上除了挂载本地目录还可以挂载各种网盘的内容，而我目前只是把本地的一个文件夹挂载到了Alist的根目录。其实Alist本质上是一个文件列表程序，主要就是提供一个网页，把本地或者其他地方的文件展示出来，供下载和上传。&lt;/p&gt;
&lt;p&gt;我在自己的Alist根目录建了一个名为share的文件夹，并尝试上传、下载了一些文件，工作都很正常。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-03/server16.webp&#34;
	width=&#34;3856&#34;
	height=&#34;1834&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;210&#34;
		data-flex-basis=&#34;504px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;但我很快发现了Alist的一个硬伤，比起网盘，Alist的定位其实更类似于一个分享文件的平台，因此它在很多方面对文件的私密性考虑不够好。正常的网盘是每个用户使用不同的存储空间，分享时单独生成分享链接，但Alist对所有用户甚至未登录的访客默认都是列出所有文件。即使我设置了只有我一个用户，并禁用了访客，问题仍然存在：同一个文件的下载链接可以在互联网上的任何一个地方使用，Alist在提供下载时并不会检验Token或者类似的东西，而是来者不拒。更要命的是，Alist的下载文件链接格式和文件绝对路径高度相关，也就是说，只要知道我的文件的绝对路径，任何人都能下载它。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，我的选择是不将我的文件直接放在根目录之下，而是放在一个名称极长的文件夹中，让这个文件夹名称起到密码的作用。当我需要分享一个文件的时候，再手动将其放到这个文件夹外的share文件夹中。但总感觉不是很安全的样子，而且很麻烦。&lt;/p&gt;
&lt;p&gt;此外还有一个问题：Cloudflare的服务在中国大陆可谓是减速器。我尝试用我的服务器ping分给我的Cloudflare节点，时间都超过300ms，而且丢包很高，tracert看了一下是走到美国去了。用Cloudflare的服务做一做博客或者Git这种对带宽和实时性要求都不高的东西还可以，但网盘这种东西用Cloudflare转发就有点难受了，但考虑到我们家其实是有公网IP的，可以对公网开放一个高位的端口来做我的网盘。于是我在路由器里配置了转发，之后实测上传文件可以突破百兆，下载也有接近40Mbps，也算是能用了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-03/server17.webp&#34;
	width=&#34;793&#34;
	height=&#34;708&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;112&#34;
		data-flex-basis=&#34;268px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-03/server18.webp&#34;
	width=&#34;799&#34;
	height=&#34;735&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;108&#34;
		data-flex-basis=&#34;260px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;这时我发现当时给Ubuntu虚拟机留的硬盘空间过小，只有64G，稍微装一点大文件我的Alist就满了。于是我决定扩容虚拟机硬盘。&lt;/p&gt;
&lt;p&gt;首先在Hyper-V里扩充虚拟磁盘的容量，这一步是非常简单的。但这样扩容之后，系统并不能立刻识别到扩大的这部分容量，因为磁盘分区仍然是按照64G来分的，因此我们用parted修改一下分区表，把主分区调整到255GB。&lt;/p&gt;
&lt;p&gt;首先用print命令查看当前硬盘分区情况：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo parted /dev/sda print
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样我们就能看到各个分区的起止位置，下面修改一下主分区的终止位置，把所有的磁盘空间用上：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo parted /dev/sda resizepart &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; 255.0GB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接下来我们用lsblk就会发现，分区sda3的大小确实变成了255G，但上面的物理卷以及Ubuntu卷组（仅包含这一个物理卷）和Ubuntu逻辑卷（是Ubuntu卷组上唯一的逻辑卷）却还是60G，这时我们运行pvresize，物理卷就会自动更新到当前分区的大小。之后再用lvresize调整Ubuntu逻辑卷的大小：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo lvresize -L +191G ubuntu-vg/ubuntu-lv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再把对逻辑卷的改动同步到文件系统：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo resize2fs /dev/ubuntu-vg/ubuntu-lv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样就可以成功扩容了。当然我们也可以在上面的lvresize中加上一个-r来自动完成下面的resize2fs。&lt;/p&gt;
&lt;p&gt;下一步我打算给我的Alist启用https服务，就用Let‘s encrypt提供的免费证书。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>孤单光量子AI翻调</title>
        <link>https://blog.clf3.org/post/lonely-light-quantum/</link>
        <pubDate>Fri, 11 Aug 2023 16:02:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/lonely-light-quantum/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/lonely-light-quantum/quantum.webp" alt="Featured image of post 孤单光量子AI翻调" /&gt;





    


&lt;div class=&#34;video-wrapper&#34;&gt;
    &lt;iframe src=&#34;https://player.bilibili.com/player.html?as_wide=1&amp;amp;high_quality=1&amp;amp;page=1&amp;bvid=BV1h44y1D7yU&#34;
            scrolling=&#34;no&#34;
            frameborder=&#34;no&#34;
            framespacing=&#34;0&#34;
            allowfullscreen=&#34;true&#34;
    &gt;
    &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;原作：欧得洋《孤单北半球》&lt;/p&gt;
&lt;p&gt;填词：张文卓&lt;/p&gt;
&lt;p&gt;调教：ClF3&lt;/p&gt;
&lt;p&gt;演唱：洛天依&lt;/p&gt;
&lt;p&gt;软件：ACE Studio&lt;/p&gt;
&lt;p&gt;《孤单光量子》是对《孤单北半球》的重新填词，最早由中国科学院光机所张文卓发布于个人博客，《孤单光量子》以量子力学为主要元素，描述了一个光子对一个电子的爱恋（或许）。&lt;/p&gt;
&lt;p&gt;我当时看到这个填词应该是2018年的暑假，看到他的博客后心血来潮，去搜索了这首歌。搜遍全网只有一个版本，那是一个用虚拟歌姬洛天依（当时应该还是V3）调的版本，那也是我最早认识天依的时候。最开始听她的声音感觉挺生硬的，但因为比较喜欢这首歌的缘故还是听了很多遍。渐渐地，我习惯了这种声音，甚至感觉这种电子合成声中有一种天然的稚嫩、冒失与可爱的感觉，后来我又听了天依的其他一些歌曲，也开始关注中文V家这个圈子。所以说，这首歌也是我的入坑曲了。在天依与ACE合作推出AI声库后，我便想着翻调一下这首曾经带给我很多快乐的歌曲，既是一种对往昔岁月的留恋，也是一个新的开始吧。&lt;/p&gt;
&lt;p&gt;因为是第一次用ACE，参数我基本没怎么动，大部分还是靠AI自己发挥的，效果竟然也出乎意料的好，于是我就把这首歌分享到B站上，也放在这里，希望有更多的人听到。&lt;/p&gt;
&lt;p&gt;附：&lt;/p&gt;
&lt;p&gt;B站本曲链接：&lt;a class=&#34;link&#34; href=&#34;https://www.bilibili.com/video/BV1h44y1D7yU&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;【【洛天依AI】孤单光量子】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;张文卓填词博文：&lt;a class=&#34;link&#34; href=&#34;https://blog.sciencenet.cn/blog-417127-326398.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://blog.sciencenet.cn/blog-417127-326398.html&lt;/a&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>在家折腾服务器的经过——MC服务器和WordPress博客</title>
        <link>https://blog.clf3.org/post/server-02/</link>
        <pubDate>Fri, 11 Aug 2023 00:04:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/server-02/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/server-02/server13.webp" alt="Featured image of post 在家折腾服务器的经过——MC服务器和WordPress博客" /&gt;&lt;p&gt;硬件方面的问题解决完，系统也已经装好了，下面就该在我的服务器上真正的部署一些服务了。&lt;/p&gt;
&lt;p&gt;首先最好解决的应该是我的世界服务器，要装的是一个大型整合包，只需先装好JDK 11的环境，再将整合包解压并运行其中的批处理脚本即可，非常的简单。但设置开机自动启动时我却遇到了一个至今未解决的问题，将这个脚本加入开机自动启动的计划中似乎并不能保证服务器重启时自动加载MC服务器，具体原因还不清楚。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-02/server11.webp&#34;
	width=&#34;1717&#34;
	height=&#34;903&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;190&#34;
		data-flex-basis=&#34;456px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;启动MC服务器后，还需要保证它可以被外网上的其他人访问，由于我家的宽带有动态的公网IP且是路由器拨号，因此只要在路由器上手动设置将外部25565端口映射到内网服务器的25565端口，再将服务器的MAC地址与IP绑定，防止DHCP导致内网IP变动。而为了保证域名始终解析到我的动态公网IP，我在服务器上进行了DDNS，即用一个Python脚本定时修改域名的DNS记录，以保证域名始终解析到当前IP。&lt;/p&gt;
&lt;p&gt;然后是远程桌面，这也很好办，防火墙放通3389，设置里打开远程桌面功能即可。出于安全考虑，我打算修改一下远程桌面的端口，但是无论怎么按照教程操作，改完之后都无法连接成功。后来我想到了一个的方法，服务器这维持3389不变，但路由器这边用别的公网端口映射到服务器的3389上就可以了。&lt;/p&gt;
&lt;p&gt;考虑到一般的服务器都是使用Linux系统，我也打算在机器上搞一个Linux虚拟机，于是我在服务器管理器上为服务器安装了Hyper-V，并在其中安装了一个使用Ubuntu server系统的虚拟机，网络模式这里选的是连接在虚拟交换机下，也就是和Windows服务器位于同一级的关系，这样路由器就能直接给我的Linux服务器分配一个内网IP。为了远程访问我的Linux虚拟机，我设置好了SSH，并在路由器防火墙上放通了自己设置的SSH端口。&lt;/p&gt;
&lt;p&gt;之后就是作为一个服务器的必备业务，也就是网页服务。这里我决定使用Cloudflare提供的tunnel实现内网穿透，而不是直接暴露公网端口，一方面是出于安全考虑，另一方面是为了防止运营商发现我用家宽提供web服务而找我的麻烦。在服务器上安装好Cloudflared，之后在Cloudflare的dashboard上配置好tunnel，并让本地的Cloudflared连接到这个tunnel。运行网页服务我一开始采用的是Windows server的IIS功能，这样就可以在本地的一些端口运行http服务，再用tunnel转发到公网上。出于安全考虑，我决定使用Cloudflare的http强转https功能，这样我的所有页面都是https的加密传输，我到Cloudflare这一段是经过私有的tunnel，可以保证安全，而Cloudflare到用户则是使用Cloudflare自己的证书进行验证。&lt;/p&gt;
&lt;p&gt;做好之后我就成功在公网上呈现了一个极为简陋的网页：&lt;/p&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://nvg.clf3.org&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://nvg.clf3.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-02/server12.webp&#34;
	width=&#34;2366&#34;
	height=&#34;1439&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;164&#34;
		data-flex-basis=&#34;394px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;之后如果想实现一点更为复杂的东西，就要写一些更复杂的HTML、CSS和JS了。所以为了一步到位，我决定安装WordPress，让这一切都可以自动生成，从而搭建起一个自己的博客。&lt;/p&gt;
&lt;p&gt;根据WordPress的官方指引，我需要安装好PHP和MySQL，Web服务器软件也最好用Apache。在网上搜索了很多安装的教程，也尝试过很多次自己配好Apache+PHP+MySQL的环境，但最终都以失败告终。正当我不知所措的时候，发现其实有类似WAMP这样适用于Windows端的Apache+PHP+MySQL集成环境，这简直是我这种技术力不是特别高的懒人的福音。我于是开始搜索WAMP的安装教程，这次非常顺利，一次就成功了。WAMP正常运行后，我将WordPress放入WAMP的www文件夹下，用浏览器访问这个文件夹，按照网页上的提示完成了WordPress的配置。终于，我看到我的第一个博客页面在localhost上成功发布了，当时我的心情可以说非常激动了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-02/server13.webp&#34;
	width=&#34;2410&#34;
	height=&#34;1079&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;223&#34;
		data-flex-basis=&#34;536px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;我在tunnel中将blog.clf3.org映射到了localhost的80端口，并从外网访问了我的博客主页。但我很快发现了新的问题，许多图片和资源都无法正常加载，经过对这些元素的Inspect，我发现它们都指向localhost下的一些资源，也就是说客户端其实在企图从自己的localhost获得这些资源，那当然是不可能的。&lt;/p&gt;
&lt;p&gt;看起来WordPress加载这些资源用的是绝对路径，这让我挺无法理解的。为了解决这个问题，我查阅了很多资料，但都没有得到满意的答案。最终，我在仪表板中设置一项找到了站点URL和WordPress URL的选项，我将二者都更改为blog.clf3.org，并在服务器hosts文件中加入将blog.clf3.org指向回环地址的项。这样一来，我在服务器上访问blog.clf3.org相当于直接访问localhost，而在客户端也可以用这个域名通过Cloudflare和tunnel访问到我的页面。&lt;/p&gt;
&lt;p&gt;但是仍有一个问题没有解决，那就是从客户端访问时图片会加载不出来。并且如果单独访问图片其实是可以加载出来的，但是页面中却并不会加载这张图片，手动重载也不行。&lt;/p&gt;
&lt;p&gt;再进行元素检查后我找到了原因：正常情况下，Cloudflare会把我的博客的http重定向到https，但博客中的资源并不会被重定向，仍是http，对于这种混合内容，大多数浏览器都会进行拦截，也就加载不出图片了，而当我单独打开图片时，Cloudflare又会把http重定向到https，也就又可以访问了。&lt;/p&gt;
&lt;p&gt;但是现在我其实也不是很能理清经过了Cloudflare之后各段用的到底是http还是https，所以就先把WordPress站点URL都改成带s的，又按照网上的说法在config文件里加入了下面3行：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$_SERVER[&amp;#39;HTTPS&amp;#39;] = &amp;#39;on&amp;#39;;
define(&amp;#39;FORCE_SSL_LOGIN&amp;#39;, true);
define(&amp;#39;FORCE_SSL_ADMIN&amp;#39;, true);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;之后把hosts里面那个DNS记录删掉就可以了，现在无论我本地管理还是其他人远程访问都是先走Cloudflare再到我这边。大家到Cloudflare肯定是https，从Cloudflare到我服务器的localhost用的tunnel，不知道里面是什么形式，localhost这肯定是http，但WordPress似乎还以为这是https？反正最后大家都能正常运行，只有我的脑子里有点混乱（&lt;/p&gt;
&lt;p&gt;最后搞好的效果就是我们现在看到的这个博客，只能说看起来还比较像那么回事，但是很多细节还不是很完善。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>在家折腾服务器的经过——系统搭建和测试跑分</title>
        <link>https://blog.clf3.org/post/server-01/</link>
        <pubDate>Thu, 10 Aug 2023 22:53:00 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/server-01/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/server-01/server01.webp" alt="Featured image of post 在家折腾服务器的经过——系统搭建和测试跑分" /&gt;&lt;p&gt;之前在和同学玩Minecraft的时候想到整一个专用服务器，正好我也希望搞一个个人博客和其他的一些东西（网盘、邮件服务器、一些实用工具网页等等），而国内云服务器的价格又很高（尤其是带宽），因此就有了自己在家整一个All in One的服务器的想法。&lt;/p&gt;
&lt;p&gt;因为整个服务器都是实验性质的，所以也就不考虑All in Boom的问题了，简单来说就是坏了拉倒（&lt;/p&gt;
&lt;p&gt;也正因如此，在服务器的选型上我决定捡一捡垃圾，好控制一下成本。一开始考虑过搞一个Dell的小主机，但是因为性价比不高而且后来不打算放宿舍就放弃了。之后想过自己组一个X99平台的台式机，用洋垃圾CPU和ECC内存。但转念一想，我本来不就是想搞一个服务器吗，为什么不一步到位捡一个X99平台的机架式服务器呢？比较了一下价格，感觉甚至比自己组装更有性价比，于是这成为了我最终选定的方案。&lt;/p&gt;
&lt;p&gt;经过一番比较，我最终确定了如下的配置：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;准系统&lt;/th&gt;
          &lt;th&gt;惠普DL360 Gen9&lt;/th&gt;
          &lt;th&gt;300-500&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;CPU&lt;/td&gt;
          &lt;td&gt;2&lt;em&gt;至强E5 2680V4（之后换成1&lt;/em&gt;V3了）&lt;/td&gt;
          &lt;td&gt;150&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;内存&lt;/td&gt;
          &lt;td&gt;4*16G DDR4 ECC内存&lt;/td&gt;
          &lt;td&gt;300&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;硬盘&lt;/td&gt;
          &lt;td&gt;4*300G SAS硬盘&lt;/td&gt;
          &lt;td&gt;90&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这一套东西都很有年头了，其中最年轻的部件生产日期也是2016年，可以说是名副其实的电子垃圾。当然，这些东西都是企业级的，当年发售的时候价格也极高，这一整套配置的价格在当年要以万为单位，如果不是被淘汰成了电子垃圾，想必我也是没有机会拥有的。&lt;/p&gt;
&lt;p&gt;说回正题，东西全收到后我立刻开始了组装，这些部件的安装难度其实并不高，首先打开服务器的顶盖：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-01/server01.webp&#34;
	width=&#34;3072&#34;
	height=&#34;4096&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;75&#34;
		data-flex-basis=&#34;180px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;把两个散热器取下就是CPU插槽，安装好CPU和内存都还很简单，但装硬盘的时候我遇到了一点麻烦，服务器的硬盘需要硬盘架才能插到前置的硬盘位上，而这个东西的硬盘架居然意想不到的贵（具体来说我的一块硬盘22，一个盘架要30以上），作为一个垃圾佬，这是我绝对不能接受的，所以我决定不用盘架装好硬盘，也就是手动对准插槽直接插上去，事实证明这也是可行的。&lt;/p&gt;
&lt;p&gt;但开机后我遇到了一个意想不到的问题，惠普的服务器需要通过iLO进行管理，但这台机器的iLO似乎有点问题。具体而言，机器启动就会报一个iLO的错误，同时修改iLO的密码时也会显示未知错误：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-01/server02.webp&#34;
	width=&#34;1706&#34;
	height=&#34;1280&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;319px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-01/server03.webp&#34;
	width=&#34;1706&#34;
	height=&#34;1280&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;319px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;这让我非常头大，我尝试了各种手段：重启、断电重启、重置iLO、把整个机器恢复出厂设置，但都没有用，询问了店家也不知道原因，最后只能退货在另一家重新买了。&lt;/p&gt;
&lt;p&gt;新机器又出现了新问题，这台机器的BIOS版本是15年的，而E5V4系列发布于16年，因此这个BIOS与CPU并不兼容，现在摆在我面前的是两个选择：升级BIOS或是换一个更老的V3CPU。在一番寻找过后，我找到了一些升级BIOS的文件，但感觉并不是很靠谱的样子。因为怕损坏BIOS而把服务器弄坏（当时并不知道主板上有备用BIOS），于是决定买一个能兼容的CPU，因为两代CPU性能差距并不大。&lt;/p&gt;
&lt;p&gt;把新（旧？）CPU装好后总算能正常进BIOS了，但又有新的问题，机器完全不认盘，新的这台机器阵列卡被拆掉了，硬盘是直插主板的，不知道这是不是不认盘的原因，于是只好买一个阵列卡再试。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-01/server04.webp&#34;
	width=&#34;1706&#34;
	height=&#34;1280&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;319px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;阵列卡装好后，进入SmartArray存储管理，可以认到盘了，把4块硬盘格式化再组一个RAID10，这样一来可以保证盘坏一块系统仍正常运行（运气好的话甚至可以坏两块），一共600GB的空间也完全够用了。但很快又有了新的问题，Windows server安装盘并不能识别这个硬盘阵列，非要我装什么驱动&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-01/server05.webp&#34;
	width=&#34;1706&#34;
	height=&#34;1280&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;133&#34;
		data-flex-basis=&#34;319px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;不过好在，我有另一个PE系统盘，进PE后可以认到硬盘，这样一来我就可以用DiskGenius分区后再用PE系统自带的工具装系统了。&lt;/p&gt;
&lt;p&gt;折腾了半天，总算装上了系统，之所以用Windows server主要是因为有GUI，个人还是不太习惯完全没有GUI的东西，而且考虑到我的两个主要需求：MC服务器和WordPress博客都可以在Windows上正常运行，其他需求完全可以用Linux虚拟机实现。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-01/server06.webp&#34;
	width=&#34;1432&#34;
	height=&#34;1049&#34;
	
	loading=&#34;lazy&#34;
	
		alt=&#34;放一张数框框的图&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;136&#34;
		data-flex-basis=&#34;327px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;装好系统后简单测试一下性能，首先是CPU，E5-2680V3，14年的古董了，用CPU-Z跑一下分，多核比我的笔记本i7-12700H差了一点，单核嘛……还不到12700H的一半，但30块的东西，也不能奢求太多了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-01/server07.webp&#34;
	width=&#34;708&#34;
	height=&#34;708&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;100&#34;
		data-flex-basis=&#34;240px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;然后是内存，4条DDR4 ECC内存，频率2133。用AIDA64的内存及缓存测试跑了一下，不过内存相关的参数我也不是很了解，也就看个乐吧。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-01/server08.webp&#34;
	width=&#34;995&#34;
	height=&#34;956&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;104&#34;
		data-flex-basis=&#34;249px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;之后是硬盘，硬盘使用了4块戴尔服务器的拆机盘，每块300G，因为年限实在太久（十年左右），怕出问题，所以组了一个RAID10阵列，也就是最后大概有600G的空间可用，速度理论上是单块硬盘的2倍，测试见下图：&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-01/server09.webp&#34;
	width=&#34;1497&#34;
	height=&#34;834&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;179&#34;
		data-flex-basis=&#34;430px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;可以看到，顺序读写性能已经接近SSD固态的水平了，但4K读写嘛，就完全没法看了。不过机械硬盘嘛，这倒也正常。&lt;/p&gt;
&lt;p&gt;最后就是简单测一下网速了，使用中科大的测速网站，结果出人意料，下载竟然有360Mbps，要知道我印象里这边一直是百兆宽带。问了一下才知道联通之前免费给我们家升级过宽带。不过上传仍然是40Mbps的小水管，但对于我这种使用需求来说也够了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.clf3.org/post/server-01/server10.webp&#34;
	width=&#34;930&#34;
	height=&#34;593&#34;
	
	loading=&#34;lazy&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;156&#34;
		data-flex-basis=&#34;376px&#34;
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Hello World</title>
        <link>https://blog.clf3.org/post/hello-world/</link>
        <pubDate>Thu, 10 Aug 2023 10:36:06 +0800</pubDate>
        
        <guid>https://blog.clf3.org/post/hello-world/</guid>
        <description>&lt;img src="https://blog.clf3.org/post/hello-world/hello-world.webp" alt="Featured image of post Hello World" /&gt;&lt;p&gt;还是决定把这篇文章保留下来，就当作是一种仪式感了吧。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hello world!&lt;/strong&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>About Me</title>
        <link>https://blog.clf3.org/page/about/</link>
        <pubDate>Thu, 10 Aug 2023 00:00:00 +0000</pubDate>
        
        <guid>https://blog.clf3.org/page/about/</guid>
        <description>&lt;p&gt;这里是ClF3，欢迎来到我的博客！&lt;/p&gt;
&lt;p&gt;如你所见，我是一个忠实的锦依卫，这个博客中也有不少的天依相关元素，感兴趣的可以找找看。&lt;/p&gt;
&lt;p&gt;我还是一个乐于瞎折腾的人，在家里拥有一台自己的机架式服务器，上面部署了一些有意思的服务，在我的博客里你也能看到我服务器的发展史和我折腾的全过程。&lt;/p&gt;
&lt;p&gt;我最近在做一些微架构相关的研究和逆向，主要针对Apple Silicon，有关的探索也可能会写成博客发出来。&lt;/p&gt;
&lt;p&gt;同时我还是一位热衷马拉松的跑者，参加过成都马拉松，北京马拉松等国内赛事，全马PB2小时56分42秒。有关跑步的一些经验和感悟也会记录在这里。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Archives</title>
        <link>https://blog.clf3.org/page/archives/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://blog.clf3.org/page/archives/</guid>
        <description></description>
        </item>
        <item>
        <title>Links</title>
        <link>https://blog.clf3.org/page/links/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://blog.clf3.org/page/links/</guid>
        <description></description>
        </item>
        <item>
        <title>Search</title>
        <link>https://blog.clf3.org/page/search/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://blog.clf3.org/page/search/</guid>
        <description></description>
        </item>
        
    </channel>
</rss>
