<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>vict0ri4</title>
  <subtitle>Linux · 网络 · 容器化部署笔记</subtitle>
  <link href="https://cyclicspace.site/" rel="alternate" type="text/html"/>
  <link href="https://cyclicspace.site/atom.xml" rel="self" type="application/atom+xml"/>
  <id>https://cyclicspace.site/</id>
  <updated>2026-10-18T00:00:00.000Z</updated>
  <entry>
    <title>解决 Gentoo 中 Corectrl 编译报错问题</title>
    <link href="https://cyclicspace.site/posts/corectrl/" rel="alternate" type="text/html"/>
    <id>https://cyclicspace.site/posts/corectrl/</id>
    <published>2026-08-27T00:00:00.000Z</published>
    <updated>2026-08-27T00:00:00.000Z</updated>
    <summary>解决因 dev-libs/quazip 移除 qt6 USE 标记导致 corectrl 无法编译的问题</summary>
    <content type="html"><![CDATA[<blockquote>
<p><strong>⚠️ 状态说明（2026-10）</strong></p>
<p>本文记录的是 2026 年 8 月 Gentoo 下 CoreCtrl 1.5.2 的一个特定编译错误。Gentoo overlay 可能已在后续版本（如 <code>1.5.2-r2</code>）中修复了该依赖问题，请优先尝试直接安装。</p>
<p>此外，CoreCtrl 项目已进入维护模式，不再添加新功能或硬件支持；如需活跃开发的 GPU 控制工具，可考虑 <strong>LACT</strong>。</p>
</blockquote>
<h1>gentoo-solution-corectrl</h1>
<h2>介绍</h2>
<p>由于dev-libs/quazip-1.5版本中直接移除了qt5和qt6两个带有Qt版本选择的 USE 标记，导致在gentoo中编译kde-misc/corectrl-1.5.2时提示以下信息：</p>
<pre><code>emerge: there are no ebuilds built with USE flags to satisfy "dev-libs/quazip[qt6]".
!!! One of the following packages is required to complete your request:
- dev-libs/quazip-1.5::gentoo (Missing IUSE: qt6)
(dependency required by "kde-misc/corectrl-1.5.2::farmboy0" [ebuild])
(dependency required by "kde-misc/corectrl" [argument])
...
</code></pre>
<p>这个错误是因为 corectrl 的 ebuild 中写死了需要 dev-libs/quazip[qt6]（即安装了 qt6 USE 标志的 quazip），但新版的 quazip 已经默认且仅支持 Qt6，因此移除了 qt6 这个 USE 标志，导致 Portage 在依赖树中找不到满足条件的包。</p>
<h2>解决方案</h2>
<h3>找到 corectrl 的 ebuild 文件</h3>
<p><code>find /var/db/repos -name "corectrl-1.5.2.ebuild" 2&gt;/dev/null</code>
不出意外的话，路径会是 /var/db/repos/farmboy0/kde-misc/corectrl/corectrl-1.5.2.ebuild。</p>
<h3>编辑 ebuild 文件</h3>
<p><code>sudo vi /var/db/repos/farmboy0/kde-misc/corectrl/corectrl-1.5.2.ebuild</code>
找到包含 dev-libs/quazip[qt6] 的那一行（通常在 RDEPEND 或 DEPEND 变量里），改为dev-libs/quazip[qt6(+)]</p>
<h3>重新生成 Manifest 文件</h3>
<p><code>cd /var/db/repos/farmboy0/kde-misc/corectrl/</code>
<code>sudo ebuild corectrl-1.5.2.ebuild manifest</code></p>
<h3>安装</h3>
<p><code>sudo emerge -av kde-misc/corectrl</code></p>
]]></content>
    <author><name>kjrin710</name></author>
    <category term="Guides"/>
  </entry>
  <entry>
    <title>在 Linux 下用 USB 网卡开 WiFi 热点</title>
    <link href="https://cyclicspace.site/posts/gentoo_hotspot/" rel="alternate" type="text/html"/>
    <id>https://cyclicspace.site/posts/gentoo_hotspot/</id>
    <published>2026-08-27T00:00:00.000Z</published>
    <updated>2026-10-18T00:00:00.000Z</updated>
    <summary>把 USB 无线网卡做成手机能连的 AP，并做成开机自启服务</summary>
    <content type="html"><![CDATA[<h1>在 Linux 下用 USB 网卡开 WiFi 热点</h1>
<blockquote>
<p>主机：Gentoo Linux（OpenRC）
日期：2026-10-18</p>
</blockquote>
<h2>前言</h2>
<p><strong>此文章用于记录我自己在一台 Gentoo 机器上用 USB 无线网卡开热点的过程。</strong></p>
<blockquote>
<p><strong>免责声明</strong></p>
<p>本文介绍的是<strong>通用 WiFi 热点（AP）搭建技术</strong>，仅适用于<strong>完全可控的网络环境</strong>，例如：</p>
<ul>
<li>家庭独立宽带</li>
<li>实验室或工作场所分配的独立网络</li>
<li>自己的流量卡</li>
</ul>
<p><strong>严禁在以下环境使用</strong>：</p>
<ul>
<li>校园网</li>
<li>公司内网</li>
<li>公共 WiFi</li>
</ul>
<p>请遵守所在网络的用户协议，任何滥用行为与本文作者无关。</p>
</blockquote>
<h2>先理解数据流向</h2>
<p>手机连上 <code>wlan0</code>，dnsmasq 给它发一个 <code>192.168.42.x</code> 的地址。之后它的上网流量到达本机，内核转发（<code>net.ipv4.ip_forward=1</code>），再做一次源地址转换（masquerade），最后从 <code>enp37s0</code> 出去。</p>
<p>整条链路上有四件事要做。hostapd 管无线信号和认证，dnsmasq 只管发 IP，NAT 管地址转换，sysctl 管打开转发。</p>
<p>其中 NAT 是绕不过去的：<code>192.168.42.0/24</code> 是私网网段，上游路由器不认识它，回程流量回不来就上不了网。区别只在于用什么工具做（nftables、iptables、firewalld、ufw 都行，见下文）。防火墙过滤则是可选的，本来就有防火墙的机器才需要额外放行。</p>
<h2>前提</h2>
<p>先确认两张网卡的名字。下面以 <code>wlan0</code> 和 <code>enp37s0</code> 为例：</p>
<pre><code>ip -br link | grep -i wl     # 无线网卡，做热点的那个
ip -br link | grep -i en     # 有线网卡，接上游的那个
</code></pre>
<p>无线网卡需要支持 AP 模式（<code>nl80211</code>）。USB 网卡里 mt7921u、rtl8812au 这些通常都支持。不支持的话，hostapd 启动时会报 <code>nl80211: Failed to set interface wlan0 into AP mode</code> 这样的错误。</p>
<p>拿不准的话，装好 <code>iw</code>（见下节）后可以用 <code>iw list</code> 查：<code>Supported interface modes</code> 下列出 <code>* AP</code> 就说明支持。</p>
<h2>依赖包</h2>
<p>要搭建这样一个热点需要安装 <code>hostapd</code>、<code>dnsmasq</code>、<code>wireless-regdb</code>、<code>iw</code> 四个软件包。<code>wireless-regdb</code> 提供各国的无线监管域数据，hostapd 里的 <code>country_code=CN</code> 要用到它；<code>iw</code> 用来确认网卡是否支持 AP 模式。</p>
<pre><code>sudo emerge -av hostapd dnsmasq wireless-regdb iw
</code></pre>
<p>另外还需要一个做 NAT 的工具。如果你的系统本来就有防火墙（nftables / iptables / firewalld / ufw），直接用它就行，不用额外装；如果什么防火墙都没有，那就装一个，本文以 nftables 为例：</p>
<pre><code>sudo emerge -av nftables
</code></pre>
<p>别的发行版包名基本也差不多，只需把安装软件的命令替换成对应发行版的即可。</p>
<h2>搭建</h2>
<h3>hostapd</h3>
<pre><code>sudo nano /etc/hostapd/hostapd_2g.conf
</code></pre>
<pre><code>interface=wlan0
driver=nl80211
ssid=MyHotspot
hw_mode=g
channel=6
ieee80211n=1
wmm_enabled=1

# 监管域
country_code=CN
ieee80211d=1

auth_algs=1
wpa=2
wpa_passphrase=&lt;你的密码&gt;
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP
rsn_pairwise=CCMP
</code></pre>
<p>记得把上面配置里的 "&lt;你的密码&gt;" 替换成你实际想设置的 WiFi 密码。</p>
<h3>dnsmasq</h3>
<pre><code>sudo nano /etc/dnsmasq.d/hotspot.conf
</code></pre>
<pre><code>interface=wlan0
bind-interfaces

# 网段需要与下面 NAT 规则里的网段一致
dhcp-range=192.168.42.100,192.168.42.200,12h

dhcp-option=3,192.168.42.1 # 本机默认网关
dhcp-option=6,223.5.5.5 # 公共 DNS，客户端不经过本机

# 记录每次 DHCP 交互，排查 "连上但分配不到 IP" 时很有用，不需要时也可以注释掉
log-dhcp
log-facility=/var/log/dnsmasq-hotspot.log
log-async=25
</code></pre>
<h3>内核转发</h3>
<pre><code>sudo nano /etc/sysctl.d/99-hotspot.conf
</code></pre>
<pre><code># 客户端要能出网，必须打开 IPv4 转发
net.ipv4.ip_forward = 1

# 我完全不转发 IPv6，有需要可以自行开启
net.ipv6.conf.all.forwarding = 0

# 接上游的有线口不接收 RA
net.ipv6.conf.enp37s0.accept_ra = 0
</code></pre>
<pre><code>sudo sysctl -p /etc/sysctl.d/99-hotspot.conf
</code></pre>
<p>放入 <code>/etc/sysctl.d/</code> 是为了让内核参数单独有个文件管，和 NAT / 防火墙规则分开。</p>
<h3>NAT</h3>
<p>客户端用的是私网地址，上游不认识，必须在本机出口上把源地址换成 <code>enp37s0</code> 的地址。</p>
<p>下面列出几种做法，挑一种即可：</p>
<p>nftables（<code>net-firewall/nftables</code> 不提供 <code>/etc/nftables.conf</code>，需要自己建。<strong>如果这个文件已经存在，则只在末尾追加下面这段，不要整体替换</strong>，因为你可能已经有一整套防火墙规则在里面）：</p>
<pre><code>sudo nano /etc/nftables.conf
</code></pre>
<pre><code>#!/usr/bin/nft -f

define WAN    = "enp37s0"
define LANNET = 192.168.42.0/24

destroy table ip hotspot_nat

table ip hotspot_nat {
	chain postrouting {
		type nat hook postrouting priority srcnat; policy accept;
		oifname $WAN ip saddr $LANNET masquerade
	}
}
</code></pre>
<pre><code>sudo nft -f /etc/nftables.conf
</code></pre>
<p>追加到已有文件时注意两点：</p>
<ul>
<li>首行的 <code>#!/usr/bin/nft -f</code> 只在新建文件时需要，追加时不要带上。</li>
<li><code>define</code> 必须在使用之前出现。两行 <code>define</code> 放进文件靠前的 <code>define</code> 区，<code>destroy table ip hotspot_nat</code> 和 <code>table ip hotspot_nat {...}</code> 放到文件末尾。</li>
</ul>
<p>整段贴在末尾会让 <code>define</code> 出现在使用之后，nft 会直接报错。</p>
<p><code>LANNET</code> 必须和上面 dnsmasq 的 <code>dhcp-range</code> 对得上，否则 masquerade 匹配不到。</p>
<p>iptables（很多系统还在用）：</p>
<pre><code>sudo iptables -t nat -A POSTROUTING -s 192.168.42.0/24 -o enp37s0 -j MASQUERADE
</code></pre>
<p>先用 <code>sudo iptables -S FORWARD | head -1</code> 看一眼策略，如果是 <code>DROP</code>，还得放行转发，否则客户端照样上不了网：</p>
<pre><code>sudo iptables -A FORWARD -i wlan0 -o enp37s0 -j ACCEPT
sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
</code></pre>
<p><code>FORWARD</code> 默认是 <code>ACCEPT</code> 的机器不用加这两条。</p>
<p>firewalld 和 ufw 都要改"默认转发策略 + masquerade"，但改的位置完全不同：</p>
<ul>
<li>
<p><strong>firewalld</strong>：把 <code>enp37s0</code> 划进 <code>external</code> 区并打开 masquerade，两条都带 <code>--permanent</code>：<code>firewall-cmd --zone=external --change-interface=enp37s0 --permanent</code>、<code>firewall-cmd --zone=external --add-masquerade --permanent</code>，最后 <code>firewall-cmd --reload</code> 生效。</p>
</li>
<li>
<p><strong>ufw</strong>：没有 zone 这个概念，要在 <code>/etc/ufw/before.rules</code> <strong>最前面</strong>加一段 nat 规则，再把 <code>/etc/default/ufw</code> 里的 <code>DEFAULT_FORWARD_POLICY</code> 改成 <code>ACCEPT</code>：</p>
<pre><code>*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 192.168.42.0/24 -o enp37s0 -j MASQUERADE
COMMIT
</code></pre>
<p>改完 <code>sudo ufw reload</code> 生效。</p>
</li>
</ul>
<p>NAT 规则怎么开机生效，取决于你用的工具，各发行版一般都有现成方案。</p>
<ul>
<li>
<p><strong>nftables</strong>：用 Gentoo 自带的 <code>net-firewall/nftables</code> 服务。它是快照模型，适合机器上只维护这一份规则的情况，按顺序执行：</p>
<pre><code>sudo nft -f /etc/nftables.conf
sudo rc-service nftables save
sudo rc-update add nftables default
</code></pre>
<p>这个服务启动时会检查 <code>/var/lib/nftables/rules-save</code>，文件不存在就直接拒绝启动。<code>rc-update</code> 只是加开机链接、不启动服务，所以 <code>save</code> 真正要赶在下次重启之前跑过。</p>
<p>快照的含义是：<code>/etc/nftables.conf</code> 只在 <code>nft -f</code> 时读一次，<code>save</code> 把当时内核里的整份规则写进 <code>rules-save</code>，开机加载的是它。所以每次改完规则，除了 <code>nft -f</code>，还要再 <code>rc-service nftables save</code> 一次，否则重启会回退到上一次快照。</p>
<p>正因为快照会把内核里<strong>所有</strong>表一起写进去，而服务加载前又会 <code>flush ruleset</code>，所以机器上要是有 tailscale、libvirt 这类自己建表的软件，就别用这个服务，改用 <a href="/posts/nftables-firewall-setup/">接管服务的做法</a>。</p>
</li>
<li>
<p><strong>iptables</strong>：<code>sudo rc-service iptables save</code> + <code>sudo rc-update add iptables default</code>。</p>
</li>
<li>
<p><strong>firewalld</strong>：本身就是常驻服务，<code>--permanent</code> 的改动自动持久，不用额外操作。</p>
</li>
</ul>
<h3>防火墙过滤（可选）</h3>
<p>如果机器没有配置防火墙，或者防火墙默认放行，等下面 <code>hotspot</code> 服务跑起来热点就能用了，这节可以跳过。</p>
<p>如果机器上有 <code>policy drop</code> 这类默认拒绝的防火墙，需要额外放行这几样：</p>
<ul>
<li><code>wlan0</code> 上的 DHCP（udp/67）：不给 dnsmasq 放行，客户端连上了也拿不到 IP</li>
<li><code>wlan0</code> → <code>enp37s0</code> 的转发</li>
<li>转发链里的 <code>ct state established,related accept</code></li>
</ul>
<p>（如果把 dnsmasq 改成下发本机地址 <code>dhcp-option=6,192.168.42.1</code>，让客户端走本机 DNS，那还要再加一条 udp/53 的放行。本文下发的是 <code>223.5.5.5</code>，客户端不经过本机，所以不用开。）</p>
<p>最后一条最容易漏：<code>policy drop</code> 只放行"客户端 → 上游"这一个方向，服务器回来的包方向是反的，匹配不到任何规则，全靠 conntrack 放行。少了它客户端能拿到 IP，但什么都连不上——DNS 查询和网页访问一起失败。</p>
<h3>hotspot</h3>
<p>新建 <code>/etc/init.d/hotspot</code>：</p>
<pre><code>#!/sbin/openrc-run
# 职责：配置无线接口 + dnsmasq + hostapd
#   - NAT / 防火墙 -&gt; 由你选定的那套工具负责
#   - ip_forward -&gt; /etc/sysctl.d/99-hotspot.conf （由 sysctl 服务加载）

rc_need="net"

IFACE=wlan0
GATEWAY=192.168.42.1

DNSMASQ_PID=/run/hotspot_dnsmasq.pid
HOSTAPD_PID=/run/hotspot_hostapd.pid

# 等某个 pidfile 出现、且对应进程还活着
_wait_pidfile() {
	local pf="$1" timeout="$2" i=0 pid
	local max=$(( timeout * 10 ))      # 每次 0.1 秒
	while [ "$i" -lt "$max" ]; do
		if [ -r "$pf" ]; then
			pid="$(cat "$pf" 2&gt;/dev/null)"
			if [ -n "$pid" ] &amp;&amp; kill -0 "$pid" 2&gt;/dev/null; then
				return 0
			fi
		fi
		sleep 0.1
		i=$(( i + 1 ))
	done
	return 1
}

start() {
	ebegin "Starting hotspot"

	# USB 网卡由 udev 异步注册，开机时未必已经就绪，所以轮询等待（上限 15 秒）
	local i=0
	while [ "$i" -lt 150 ]; do
		ip link show "$IFACE" &gt;/dev/null 2&gt;&amp;1 &amp;&amp; break
		sleep 0.1
		i=$(( i + 1 ))
	done
	if ! ip link show "$IFACE" &gt;/dev/null 2&gt;&amp;1; then
		eerror "接口 $IFACE 在 15 秒内未出现，热点无法启动"
		return 1
	fi

	ip link set "$IFACE" up
	ip addr add "$GATEWAY/24" dev "$IFACE" 2&gt;/dev/null

	# --- dnsmasq ---
	dnsmasq --conf-file=/etc/dnsmasq.d/hotspot.conf --pid-file="$DNSMASQ_PID"
	if ! _wait_pidfile "$DNSMASQ_PID" 5; then
		eerror "dnsmasq 启动失败或未在 5 秒内就绪"
		return 1
	fi

	# --- hostapd ---
	hostapd -B -P "$HOSTAPD_PID" /etc/hostapd/hostapd_2g.conf
	if ! _wait_pidfile "$HOSTAPD_PID" 10; then
		ewarn "hostapd 未在 10 秒内就绪（可能需要更久初始化射频），但它已在后台运行"
	fi

	eend 0
}

stop() {
	ebegin "Stopping hotspot"
	pkill -f "hostapd.*hostapd_2g.conf" 2&gt;/dev/null || true
	pkill -f "dnsmasq.*hotspot.conf" 2&gt;/dev/null || true
	rm -f "$HOSTAPD_PID" "$DNSMASQ_PID" 2&gt;/dev/null || true
	ip addr del "$GATEWAY/24" dev "$IFACE" 2&gt;/dev/null || true
	eend 0
}
</code></pre>
<h3>启用服务</h3>
<pre><code>sudo chmod +x /etc/init.d/hotspot
sudo rc-update add hotspot default
sudo rc-service hotspot start
</code></pre>
<p><code>hotspot</code> 是 <code>rc_need="net"</code>，等网络就绪才会启动。</p>
<p>如果你是用 nftables 管理 NAT，还要把它加进开机流程，做法见前面 NAT 那节。</p>
<p>用 systemd 的发行版则需把上面的 <code>start</code>/<code>stop</code> 写成 service unit。别的 OpenRC 发行版思路相同，但网络服务名和配置路径未必一致——本文的 <code>rc_need="net"</code> 依赖 Gentoo netifrc 提供的 <code>net</code> 虚拟服务，Alpine 上对应的服务叫 <code>networking</code>，照抄前先确认。</p>
<h2>验证</h2>
<p>服务起来之后，按顺序检查，哪一步断了就对应哪一段配置：</p>
<p><strong>第一步：服务都活着。</strong> 本机上看：</p>
<pre><code>rc-service hotspot status
pgrep -af hotspot          # 应该能看到 dnsmasq 和 hostapd 各一个
ip -4 addr show wlan0      # 应该能看到 192.168.42.1/24
</code></pre>
<p><code>wlan0</code> 上没有 <code>192.168.42.1/24</code>，说明 <code>hotspot</code> 的 <code>start</code> 没走完，往上翻它启动时的报错。</p>
<p>顺手确认 NAT 规则在：nftables 用 <code>sudo nft list table ip hotspot_nat</code>，iptables 用 <code>sudo iptables -t nat -L POSTROUTING -n</code>，能看到 masquerade 就行。</p>
<p><strong>第二步：手机拿到了地址。</strong> 手机连上热点后，看它分配的 IP 是不是 <code>192.168.42.100</code>–<code>192.168.42.200</code> 之间的地址。</p>
<ul>
<li>如果连不上热点：hostapd 没起来，看「无线接口被占用」和「网卡被 rfkill 软阻塞」两节</li>
<li>如果连上了但一直转圈拿不到 IP：dnsmasq 没应答，看 <code>/var/log/dnsmasq-hotspot.log</code></li>
</ul>
<p><strong>第三步：能通到上游。</strong> 在手机上依次 ping 三个地址，断在哪一层很清楚：</p>
<table>
<thead>
<tr>
<th>目标</th>
<th>通了说明</th>
<th>不通说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>192.168.42.1</code></td>
<td>到本机这一跳正常</td>
<td><code>wlan0</code> 地址或 dnsmasq 网关选项有问题</td>
</tr>
<tr>
<td><code>223.5.5.5</code></td>
<td>转发和 NAT 都正常</td>
<td><code>ip_forward</code> 没开，或 NAT / 转发规则没生效</td>
</tr>
<tr>
<td>任意域名</td>
<td>DNS 解析也正常</td>
<td>DNS 不通，检查 <code>dhcp-option=6</code> 下发的是否可达</td>
</tr>
</tbody>
</table>
<p><code>192.168.42.1</code> 通、<code>223.5.5.5</code> 不通，先查 NAT 和转发这一层：回到 NAT 那节确认规则真的加载了（<code>nft list ruleset</code> 或 <code>iptables -t nat -L POSTROUTING -n</code>），以及 <code>net.ipv4.ip_forward</code> 是 <code>1</code>。</p>
<p><strong>最后：重启再走一遍。</strong> 上面几步只证明了这一次运行是好的。快照没 <code>save</code>、<code>rc-update</code> 没加上、dhcpcd 又抢了地址，这些问题全都要等重启才会暴露。<code>sudo reboot</code> 之后按第一步和第三步复查一遍，都正常才算真的搭好了。</p>
<h2>故障排除</h2>
<h3>无线接口被占用</h3>
<p>如果这块网卡之前当客户端用过，<code>net.wlan0</code> 服务或 <code>wpa_supplicant</code> 进程可能还握着它。此时 hostapd 会报 <code>nl80211: Interface wlan0 is in use</code> 这样的错误。先确认：</p>
<pre><code>rc-service net.wlan0 status
pgrep -a wpa_supplicant
</code></pre>
<p>如果有就停掉，再重启热点：</p>
<pre><code>sudo rc-service net.wlan0 stop
sudo pkill wpa_supplicant
sudo rc-service hotspot restart
</code></pre>
<h3>网卡被 rfkill 软阻塞</h3>
<p><code>rfkill list</code> 里 <code>Soft blocked: yes</code> 时 hostapd 也起不来：</p>
<pre><code>rfkill list
sudo rfkill unblock wlan
</code></pre>
<p>如果看到的是 <code>Hard blocked: yes</code>，那是机身上的物理开关或 BIOS 关掉了无线，软件解不开，得先去把开关打开。</p>
<h3>dhcpcd 抢占地址</h3>
<p>dhcpcd 可能会在这块网卡上尝试 DHCP，失败后留下一个 <code>169.254.x.x</code> 的地址和 <code>/16</code> 路由。因此需要在 <code>/etc/dhcpcd.conf</code> 里加一行：</p>
<pre><code>denyinterfaces wlan0
</code></pre>
<p>然后重启 dhcpcd，注意要加 <code>--nodeps</code>。dhcpcd 被 <code>hotspot</code>、<code>libvirtd</code>、<code>tailscale</code> 的服务引用，普通 <code>rc-service dhcpcd restart</code> 会让 OpenRC 先把这些依赖服务停掉，却不会自动拉起来，结果是热点、tailscale、虚拟机一起掉线，<code>wlan0</code> 上的 <code>192.168.42.1/24</code> 也会消失。</p>
<pre><code>sudo rc-service dhcpcd --nodeps restart
ip -4 addr show wlan0     # 确认没有 169.254.x.x 残留
</code></pre>
<p>如果之前已经产生过 <code>169.254.x.x</code>，<code>denyinterfaces</code> 不会自动删掉它，只能手动清理：</p>
<pre><code>sudo ip addr del 169.254.x.x/16 dev wlan0
</code></pre>
<h2>日常管理</h2>
<pre><code>sudo rc-service hotspot  start     # 开热点
sudo rc-service hotspot  stop      # 关热点（NAT 规则保留，但此时无流量匹配）
sudo rc-service hotspot  restart   # 重启热点
</code></pre>
<p>改完 NAT / 防火墙规则后，按你所用工具的方式重载。以 nftables 为例：</p>
<pre><code>sudo nft -f /etc/nftables.conf     # 立即生效
sudo nft list ruleset              # 确认规则在
</code></pre>
<p><strong>如果用的是前面提到的 Gentoo 官方快照模型，还要再 <code>sudo rc-service nftables save</code> 一次</strong>，否则重启后会回退到上一次快照。</p>
<p>周围 AP 多、连接不稳时可以换信道。默认 <code>channel=6</code>，换成 1 或 11 通常明显好些，改完执行 <code>sudo rc-service hotspot restart</code> 生效。</p>
]]></content>
    <author><name>kjrin710</name></author>
    <category term="Guides"/>
  </entry>
  <entry>
    <title>我在gentoo下的nftables防火墙设计</title>
    <link href="https://cyclicspace.site/posts/nftables-firewall-setup/" rel="alternate" type="text/html"/>
    <id>https://cyclicspace.site/posts/nftables-firewall-setup/</id>
    <published>2026-06-19T00:00:00.000Z</published>
    <updated>2026-10-17T00:00:00.000Z</updated>
    <summary>在Gentoo/OpenRC上接管官方nftables服务：把手写规则作为唯一来源、用CONFIG_PROTECT机制在升级中保住自己的脚本，以及与自带规则的服务如何共存。</summary>
    <content type="html"><![CDATA[<h2>前言</h2>
<p><strong>此文章用于记录我自己维护防火墙的方法，记录在Gentoo/OpenRC环境下维护防火墙时逐渐形成的思路。</strong></p>
<hr />
<h2>一些说明</h2>
<p>gentoo发行版有自己官方的nftables服务，通常执行<code>rc-update add nftables default</code>即可使用，但随着我的需求增大，不少端口我都需要手动控制，比如sunshine串流，热点配置等，此时官方的save/restore模型就不够用了。</p>
<p>portage中有<code>etc-update</code>机制，正确设置可以保证修改不会被重新<code>emerge nftables</code>冲掉。下面我先说官方的配置具体是怎样的，再说怎么接管nftables服务。</p>
<hr />
<h2>官方配置</h2>
<p>gentoo 的 nftables 服务是快照模型：先把规则装进内核，然后</p>
<pre><code>sudo rc-service nftables save
</code></pre>
<p>它会把 <code>nft list ruleset</code> 的输出写进 <code>/var/lib/nftables/rules-save</code>，开机时再从这个文件读回来。ebuild 装完提示的也是这个用法。</p>
<p>加载那一步实际执行的是</p>
<pre><code>printf 'flush ruleset\ninclude "%s"\n' "${NFTABLES_SAVE}" | nft -f -
</code></pre>
<p><code>flush ruleset</code> 是写死在 <code>/usr/libexec/nftables/nftables.sh</code> 里的，改 <code>/etc/conf.d/nftables</code> 也去不掉。在快照模型下这么做其实是合理的，因为快照本身是全量的，机器上所有表都在里面，清空再整体装回来也不会丢东西。
但我的用法不是这样。tailscale、libvirt 等软件会往内核里加入自己的防火墙配置，这种情况下官方的一条 <code>flush ruleset</code> 就会把它们的表一起清掉，结果可想而知，tailnet 不通、虚拟机没网，用<code>rc-service</code>看状态又全是 started，很容易往错的方向查。为了避免这些问题，所以我接下来打算接管官方服务。</p>
<h2>接管官方服务</h2>
<p><code>/etc/init.d/nftables</code> 属于 <code>net-firewall/nftables</code> 这个包，但它在 <code>/etc</code> 里，而 <code>/etc</code> 是配置目录，不是包来管理的。portage 对待配置目录的规则写在 emerge(1) 里：</p>
<blockquote>
<p>The purpose of this feature is to prevent new package installs from clobbering existing configuration files.</p>
</blockquote>
<p>具体做法是，安装时如果发现同名文件已经存在，就把要装的那个改名成 <code>._cfg0000_foo</code> 放在旁边，等用户自己决定怎么合并。所以升级一个包<strong>不会</strong>动改过的文件，只会在旁边多放一个待合并的新版本。这是设计出来的行为，不是副作用。</p>
<p>而且这里还有一层。make.conf(5) 里有个默认开启的 FEATURES：</p>
<blockquote>
<p>config-protect-if-modified
This causes the CONFIG_PROTECT behavior to be skipped for files that have not been modified since they were installed.</p>
</blockquote>
<p>意思是，如果某个文件从装好到现在都没有被修改过(mtime)，portage 就会认为没必要保护它，升级时直接换成新的；该文件一旦修改过，它从此就会进入保护状态，生成 <code>._cfg0000_</code> 并询问用户选择如何处理。</p>
<p>所以直接把自己的逻辑写进 <code>/etc/init.d/nftables</code> 是比较合理的做法，服务名保持不变，用起来也几乎感受不到区别。</p>
<p>但要千万注意执行etc-update命令后提示到此文件需要更新时要看清楚，千万不要选-3。选-3会用官方脚本把你这份覆盖掉，而官方脚本加载时执行的是 <code>flush ruleset</code> 加上 include 那个 0 字节的 <code>rules-save</code>，结果将会是<strong>清空全部表、且不加载任何规则，机器变成完全没有防火墙</strong>。而且 <code>-3</code> 是全局覆盖，作用于整个扫描范围，一次会把所有包所有待合并文件全部覆盖。为了保险还是建议手动创建备份文件<code>cp -a /etc/init.d/nftables /etc/init.d/nftables.bak</code>，用于防止手贱选了-3选项配置被清除后没有及时做备份。</p>
<h2>服务脚本</h2>
<p>以下配置仅供参考：</p>
<pre><code>#!/sbin/openrc-run
# ============================================================================
#  /etc/init.d/nftables
#
#  作用: 加载 /etc/nftables.conf, 只管理我自己的表。
#
#  升级注意:
#    /etc 在 CONFIG_PROTECT 里, 升级本包时会在旁边生成
#    /etc/init.d/._cfg0000_nftables。合并时选 -7 即可保留本脚本:
#        sudo etc-update /etc/init.d
# ============================================================================

description="nftables firewall (single source: /etc/nftables.conf)"

NFT_FILE="/etc/nftables.conf"

# 写成 "族:表名" 的形式, 空格分隔; 要与 nftables.conf 里的定义保持一致。
MY_TABLES="inet:&lt;过滤表&gt; ip:&lt;NAT表&gt;"

extra_commands="check"
extra_started_commands="check reload"

depend() {
	need localmount
	before net
}

check() {
	ebegin "语法检查 ${NFT_FILE}"
	nft -c -f "${NFT_FILE}"
	eend $? "语法/语义有问题, 上面是报错位置"
}

start() {
	ebegin "加载 nftables 规则 (${NFT_FILE})"
	nft -f "${NFT_FILE}"
	eend $? "加载失败 —— 当前处于无防火墙状态"
}

stop() {
	ebegin "移除本服务的表 (${MY_TABLES})"
	for t in ${MY_TABLES}; do
		fam="${t%%:*}"
		name="${t##*:}"
		# 先确认存在再删, 保证 stop 可以重复执行。
		if nft list table "${fam}" "${name}" &gt;/dev/null 2&gt;&amp;1; then
			nft delete table "${fam}" "${name}" || true
		fi
	done
	eend 0
}

reload() {
	ebegin "重新加载 nftables 规则 (${NFT_FILE})"
	nft -f "${NFT_FILE}"
	eend $? "重载失败, 旧规则仍在生效"
}
</code></pre>
<p>记得将<code>MY_TABLES</code> 两处占位符换成在 <code>/etc/nftables.conf</code> 里定义的实际表名，否则 <code>stop</code> 时查不到表会直接跳过。</p>
<p>写好后再给<code>/etc/init.d/nftables</code>可执行权限，加进 default 运行级，再启动一次：</p>
<pre><code>sudo chmod +x /etc/init.d/nftables
sudo rc-update add nftables default
sudo rc-service nftables start
</code></pre>
<h2>配合其他软件的防火墙配置来管理自己的防火墙规则</h2>
<p>tailscale、libvirt 等等其他软件都有自己的一套防火墙配置。这些配置通常不需要也不建议用户来手动更改，它们启动停止时自己会处理。</p>
<p>所以用户在管理nftables时只需遵守以下原则：</p>
<p>1、不随意执行sudo nft flush ruleset</p>
<p>2、排除防火墙问题时检查是否与软件自带的防火墙配置有冲突</p>
<pre><code>sudo nft list tables
sudo nft list chain ip filter
</code></pre>
<p><code>nft list tables</code> 列出的表通常比自己的多，看一眼链名就能认出是谁建的，比如 <code>ts-input</code>、<code>ts-forward</code> 是 tailscale 的。自己的表名带上能一眼区分的名字，查问题的时候省事。</p>
<p>还有一类误判是容器。网上很多配置会写 <code>iifname "podman*" accept</code>、<code>oifname "veth*" accept</code> 之类的转发规则，但那是 rootful 加 bridge 网络才有意义。用 rootless 配 pasta 的话，容器流量在内核看来就是本机进程自己发出去的，走 output 链，根本不经过 forward。那些规则不会生效，纯粹是死代码。先看一眼有没有网桥接口就知道自己属于哪种：</p>
<pre><code>ip -br link
</code></pre>
<h2>日常维护</h2>
<p>改完先检查再加载：</p>
<pre><code>sudo nft -c -f /etc/nftables.conf
sudo rc-service nftables reload
</code></pre>
<p><code>ct state established,related accept</code> 每个链都应该要有。它放行本机主动发起的连接的回程包，不用给每个服务写双向规则。forward 链上漏了这条，表现是有 IP、能解析域名，但所有网页都打不开 —— 因为回程包没有任何规则能匹配上。</p>
<p>重建表用 <code>destroy</code> 而不是 <code>flush</code>：</p>
<pre><code>destroy table inet &lt;过滤表&gt;
destroy table ip &lt;NAT表&gt;
</code></pre>
<p><code>destroy</code> 只删指定的表，表不存在也不报错，适合每次全量加载；<code>flush ruleset</code> 会把别人的表一起清掉。</p>
<p>平时不用手动 start，服务已经在 default 运行级里了，开机自己会加载。<code>start</code> 只在手动 stop 过之后才需要。</p>
<p>若想加一个新服务的端口，顺序是先用</p>
<pre><code>ss -tulnp | grep &lt;关键字&gt;
</code></pre>
<p>看清楚它实际监听的是什么协议、哪个端口，再把对应端口加进 <code>/etc/nftables.conf</code>。</p>
]]></content>
    <author><name>kjrin710</name></author>
    <category term="Guides"/>
  </entry>
  <entry>
    <title>Gentoo 安装记录</title>
    <link href="https://cyclicspace.site/posts/gentoo_install/" rel="alternate" type="text/html"/>
    <id>https://cyclicspace.site/posts/gentoo_install/</id>
    <published>2026-03-15T00:00:00.000Z</published>
    <updated>2026-03-15T00:00:00.000Z</updated>
    <summary>记录一次 Gentoo 安装过程及配置（Btrfs + Openrc + 自定义内核）</summary>
    <content type="html"><![CDATA[<h1>gentoo-installation-steps</h1>
<h2>gentoo linux安装记录</h2>
<h3>引言</h3>
<p>记录一次安装gentoo的过程，文档中可能存在不太合理的部分。请以官方文档为准，本篇文章只能作为参考。
先说我的安装条件<br />
<strong>Gentoo版本</strong>： [Gentoo Linux 23.0/openrc]<br />
<strong>内核版本</strong>： [7.2.2-cachyos-r4]<br />
<strong>文件系统</strong>： [btrfs,vfat]<br />
<strong>启动方式</strong>： [UEFI+grub]</p>
<h3>硬件信息</h3>
<p>处理器 [AMD Ryzen r3 3300x]<br />
显卡 [AMD Radeon RX5700]<br />
内存 [16GB DDR4]<br />
硬盘 [256GB NVMe SSD]</p>
<h3>准备工作</h3>
<p>选择合适的方法安装Gentoo<br />
Gentoo可以以许多不同的方式安装。<br />
它可以从官方Gentoo安装介质（如我们的可引导ISO文件）下载和安装。安装介质可以安装在USB盘上或通过网络引导环境访问。 或者，Gentoo可以从非官方介质安装，如已安装的发行版或非Gentoo可启动磁盘（如 Linux Mint）。<br />
Gentoo LiveGUI提供 KDE 桌面环境的 LiveGUI 可能会使一些用户更容易安装 Gentoo。除了提供好用的桌面环境，LiveGUI 通过 NetworkManager 组件也提供了简单的 WiFi 设置。<br />
我是先去https://mirrors.ustc.edu.cn/gentoo/releases/amd64/autobuilds/ 下载iso镜像，选install-amd64-minimal和livegui-amd64都行。我用livegui-amd64，方便复制粘贴。</p>
<p>下载后使用烧录工具将镜像写入到u盘。</p>
<h3>进入livecd</h3>
<p>插入写好镜像的u盘，进入live系统，连接wifi或插上网线。</p>
<p>打开konsole命令控制台，输入<br />
<code>sudo passwd</code> # 先设置一个简单管理密码，因为这只是一个临时使用的live系统，非常复杂的密码反而会引起不便。</p>
<p>输入<code>su</code>并输入刚才的设置的密码进入root用户。</p>
<p>接下来给磁盘分区，我用的是fdisk工具，livecd中也自带parted等分区工具，看个人习惯来使用吧。<br />
**注意！在分区之前务必及时备份数据！<br />
<code>fdisk /dev/nvme0n1</code>  # 如果是sata硬盘就应该是/dev/sda1<br />
以下是我的分区方案（仅供参考）</p>
<pre><code>Disk /dev/nvme0n1: 232.89 GiB, 250059350016 bytes, 488397168 sectors
Disk model: WDC WDS250G2B0C-00PXH0
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 2A4768D8-9813-4CE2-BE64-1CB13C1F959A

Device           Start       End   Sectors   Size Type
/dev/nvme0n1p1    2048   1050623   1048576   512M EFI System
/dev/nvme0n1p2 1050624 488396799 487346176 232.4G Linux filesystem
</code></pre>
<p>格式化分区<br />
<code>mkfs.vfat -F 32 /dev/nvme0n1p1</code> # 给nvme0n1p2使用vfat文件系统<br />
<code>mkfs.btrfs -f /dev/nvme0n1p2</code> # 给nvme0n1p1使用btrfs文件系统</p>
<p>之后给nvme0n1p2细分btrfs子卷<br />
<code>mkdir -p /mnt/btrfs</code><br />
<code>mount -o subvolid=5 /dev/nvme0n1p2 /mnt/btrfs</code><br />
<code>cd /mnt/btrfs</code><br />
<code>btrfs subvolume create @</code><br />
<code>btrfs subvolume create @home</code><br />
<code>btrfs subvolume create @boot</code><br />
<code>btrfs subvolume create @var</code><br />
<code>btrfs subvolume create @snapshots</code><br />
<code>btrfs subvolume set-default @ /mnt/btrfs</code>   # 设 @ 为默认子卷<br />
<code>btrfs subvolume list /mnt/btrfs</code>            # 验证一下<br />
<code>umount /mnt/btrfs</code></p>
<p>挂载<br />
<code>mount -o subvol=@,compress=zstd:1,commit=30,ssd,discard=async,space_cache=v2 /dev/nvme0n1p2 /mnt/gentoo</code><br />
<code>mkdir -p /mnt/gentoo/{boot/efi,home,var}</code><br />
<code>mount -o subvol=@boot   /dev/nvme0n1p2 /mnt/gentoo/boot</code><br />
<code>mount -o subvol=@home,nodatacow /dev/nvme0n1p2 /mnt/gentoo/home</code><br />
<code>mount -o subvol=@var,nodatacow   /dev/nvme0n1p2 /mnt/gentoo/var</code><br />
<code>mount -o subvol=@snapshots       /dev/nvme0n1p2 /mnt/gentoo/.snapshots</code><br />
<code>mount /dev/nvme0n1p1 /mnt/gentoo/boot/efi </code></p>
<p>进到刚挂载好的目录<br />
<code>cd /mnt/gentoo</code></p>
<h3>安装 Gentoo 安装文件</h3>
<p>下载stage3压缩包<br />
<code>links https://mirrors.ustc.edu.cn/gentoo/releases/amd64/autobuilds/</code>  #在里面选择显示日期和时间的目录后回车，比如20260308T170100Z，这个显示日期和时间的目录一般会有好几个，我一般选择的是最新的，避免更新时间长。例如，我用systemd就选择stage3-amd64-systemd-20260308T170100Z.tar.xz</p>
<p><code>tar xpvf stage3-amd64-systemd-20250914T170345Z.tar.xz</code> # 解压</p>
<p><code>nano -w /mnt/gentoo/etc/portage/make.conf</code>  # 设置gcc编译选项</p>
<pre><code># detailed example.
COMMON_FLAGS="-march=native -O3 -pipe -finline-functions" #我用gcc -O3优化
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
FCFLAGS="${COMMON_FLAGS}"
FFLAGS="${COMMON_FLAGS}"
#CPU_FLAGS_X86="" # 此项待会再填
MAKEOPTS="-j9 -l8" #3300x有8线程，如果没有设置zram怕内存溢出导致livecd卡死就保守一点用-j6

# NOTE: This stage was built with the bindist USE flag enabled

# This sets the language of build output to English.
# Please keep this setting intact when reporting bugs.
LC_MESSAGES=C.utf8

CHOST="x86_64-pc-linux-gnu"
EMERGE_DEFAULT_OPTS="--with-bdeps=y --verbose=y --keep-going"
ACCEPT_LICENSE="*"
ACCEPT_KEYWORDS="amd64"
L10N="en-US zh-CN en zh"
LINGUAS="en-US zh-CN en zh"
AUTO_CLEAN="yes"
GRUB_PLATFORMS="efi-64"
VIDEO_CARDS="amdgpu radeonsi"
ALSA_CARDS="hda-intel"
INPUT_DEVICES="evdev"

PORTAGE_NICENESS="15"

GENTOO_MIRRORS="https://mirrors.tuna.tsinghua.edu.cn/gentoo https://mirrors.zju.edu.cn/gentoo/ http://mirrors.zju.edu.cn/gentoo/ https://mirrors.ustc.edu.cn/gentoo/ https://mirrors.nju.edu.cn/gentoo/ http://mirrors.nju.edu.cn/gentoo/ https://mirror.lzu.edu.cn/gentoo http://mirror.lzu.edu.cn/gentoo https://mirrors.aliyun.com/gentoo/ http://mirrors.aliyun.com/gentoo/ https://mirrors.163.com/gentoo/ http://mirrors.163.com/gentoo/ "


#gentoo的特色之一，gentoo的大部分软件包都会有不同的USE标志，在这里的设置是全局的，意思是你要给所有支持这个USE标志的软件包都默认启用这个标志，如果你只希望给单独的软件包设置特定的USE标志，别急，我后面点会讲到。
#USE="-pulseaudio -iptables -pipewire -jack -kde -gnome -xfce -wayland fortran lto pgo graphite openmp minizip elogind dbus policykit X cjk vdpau vaapi vulkan egl gles2 glfw opengl openal alsa nftables" #这是我会用到的USE标志，仅供参考。而且不推荐在刚安装系统时就同时启用这么多标志。这些后续我会一点一点的加上。
</code></pre>
<p>配置软件镜像源
<code>mkdir -p -v /mnt/gentoo/etc/portage/repos.conf</code><br />
<code>cp -v /mnt/gentoo/usr/share/portage/config/repos.conf /mnt/gentoo/etc/portage/repos.conf/gentoo.conf</code></p>
<p><code>nano -w /mnt/gentoo/etc/portage/repos.conf/gentoo.conf</code></p>
<pre><code>[DEFAULT]
main-repo = gentoo
sync-uri = rsync://mirrors.ustc.edu.cn/gentoo-portage #加入中国源

[gentoo]
location = /var/db/repos/gentoo
...
</code></pre>
<h3>安装 Gentoo 基础系统</h3>
<p>复制DNS信息<br />
<code>cp --dereference /etc/resolv.conf /mnt/gentoo/etc/</code></p>
<p>挂载系统必要环境，并进入Chroot环境<br />
<code>mount --types proc /proc /mnt/gentoo/proc</code><br />
<code>mount --rbind /sys /mnt/gentoo/sys</code><br />
<code>mount --make-rslave /mnt/gentoo/sys</code><br />
<code>mount --rbind /dev /mnt/gentoo/dev</code><br />
<code>mount --make-rslave /mnt/gentoo/dev</code><br />
<code>mount --rbind /run /mnt/gentoo/run</code><br />
<code>mount --make-rslave /mnt/gentoo/run</code><br />
<code>chroot /mnt/gentoo /bin/bash</code><br />
<code>mkdir -p /var/db/repos/gentoo</code><br />
<code>env-update</code><br />
<code>source /etc/profile</code><br />
<code>export PS1="(chroot) ${PS1}"</code></p>
<p>安装 Gentoo ebuild 存储库的快照。该快照包含一组文件，这些文件通知 Portage 可用的软件标题（用于安装）、系统管理员可以选择的配置文件、打包或配置文件特定的新闻项目等。<br />
<code>emerge-webrsync</code></p>
<p>安装cpuid2cpuflags，检测cpu指令集<br />
<code>emerge --ask app-portage/cpuid2cpuflags</code><br />
<code>cpuid2cpuflags</code>  # 将输出值全部拷贝到/mnt/gentoo/etc/portage/make.conf中，作为“CPU_FLAGS_X86= ”的值，并取消对“CPU_FLAGS_X86= ”这一行的注释。</p>
<p>配置系统时区<br />
<code>nano -w /etc/locale.gen</code><br />
将以下几项取消注释，如果没有就手动加上</p>
<pre><code>en_US ISO-8859-1
en_US.UTF-8 UTF-8
zh_CN GBK 
zh_CN.UTF-8 UTF-8
</code></pre>
<p>下一步是运行 locale-gen 命令。此命令生成 /etc/locale.gen 文件中指定的所有语言环境。<br />
<code>locale-gen</code></p>
<h3>（可选）重新将整个基本系统从stage1编译到stage3</h3>
<p>目的是把原来官方提供的所有组件替换成自己编译的（包括GCC编译器和所有基本系统组件），这样一来整个系统的所有程序和组件都是针对自己电脑CPU架构优化编译的了，争取性能最大化。唯一的坏处就是会花费更多的精力和时间。如果你只是想简单的安装gentoo系统体验一下，就推荐跳过此步骤。<br />
<code>./var/db/repos/gentoo/scripts/bootstrap.sh</code>  # 这个脚本执行完检测后重新编译安装emerge包管理器，在我这台机器上花费了十多分钟的时间。</p>
<p>重新编译安装完emerge包管理器后，bootstrap.sh脚本还会继续检测当前系统环境，最后很可能会警告提示你当前系统里的gcc编译器缺少对fortran的支持、zlib库缺少对minizip的支持，然后退出脚本。<br />
<code>nano -w /etc/portage/make.conf</code></p>
<pre><code>...
USE="fortran lto pgo graphite openmp minizip"
</code></pre>
<p>先启用以上USE标志，其他USE标志继续注释着先。</p>
<p><code>emerge --ask gcc</code> # 重新编译gcc，你会看到你会看到刚才加上的那些use标志高亮了，意味着这次编译会应用上这些use标志。这会花费很长时间，大约2-3个小时吧。</p>
<p>之后退出当前chroot环境再重新进入。<br />
<code>exit</code><br />
<code>chroot /mnt/gentoo /bin/bash</code><br />
<code>env-update &amp;&amp; source /etc/profile &amp;&amp; export PS1="(chroot) ${PS1}"</code></p>
<p>重新运行一次脚本检测。<br />
<code>./var/db/repos/gentoo/scripts/bootstrap.sh</code></p>
<p>不出意外的话最后会成功通过检测，并提示你系统已经成功“bootstrapped”了，并要求你执行emerge -e @system。那我们就从stage2到stage3（重新编译：基本系统的所有组件base system）。<br />
<code>emerge -e @system</code>
<code>emerge -e @world</code>  # 此过程将会非常耗时，3300x编译大约用了2个半小时</p>
<h3>接下来，正式安装gentoo系统 （如果选择跳过上面的可选步骤就直接从这里继续）</h3>
<p>到这里就可以把make.conf文件中剩下的use都启用上了，然后更新一下。<br />
<code>emerge -avuDN @world</code></p>
<p><code>eselect profile list</code><br />
<code>eselect profile set X</code>  # 我打算用openrc+窗口管理器，所以选了default/linux/amd64/23.0/，有其他需求的就选择其他对应的profile<br />
<code>env-update</code><br />
如果profile发生了改变，也应该再次更新软件包。<br />
<code>emerge -avuDN @world</code></p>
<p>设置系统locale<br />
<code>eselect locale list</code><br />
<code>eselect locale set X</code>  # 这里建议选择en-US.utf8，大部分TTY终端都不支持中文。</p>
<p>创建并配置/etc/fstab文件，用以指示系统开机自动挂载的必要设备/分区<br />
<code>blkid &gt;&gt; /etc/fstab</code>  # 将输出结果追加到fstab配置文件末尾，然后根据追加的内容进行下述修改<br />
<code>nano -w /etc/fstab</code>  # 请参考我的配置，建议使用uuid的形式设置（不建议使用/dev/sdX？的形式）(是uuid，而不是partuuid哦)</p>
<pre><code># &lt;fs&gt;			                           &lt;mountpoint&gt;	&lt;type&gt; &lt;opts&gt;		                                              &lt;dump&gt; &lt;pass&gt;
UUID=bd7589dd-daa7-4245-9ce5-4d1cc9e128cb  /            btrfs  defaults,noatime,ssd,commit=60,nodiscard,subvol=@          0 0
UUID=bd7589dd-daa7-4245-9ce5-4d1cc9e128cb  /home        btrfs  defaults,noatime,ssd,commit=60,nodiscard,subvol=@home      0 0
UUID=bd7589dd-daa7-4245-9ce5-4d1cc9e128cb  /boot        btrfs  defaults,noatime,ssd,commit=60,nodiscard,subvol=@boot      0 0
UUID=bd7589dd-daa7-4245-9ce5-4d1cc9e128cb  /var         btrfs  defaults,noatime,ssd,commit=60,nodiscard,subvol=@var       0 0
UUID=bd7589dd-daa7-4245-9ce5-4d1cc9e128cb  /.snapshots  btrfs  defaults,noatime,ssd,commit=60,nodiscard,subvol=@snapshots 0 0
tmpfs  /tmp  tmpfs  defaults,noatime,mode=1777,size=4G  0 0

</code></pre>
<p>安装必须的文件系统支持，否则无法访问硬盘上的分区！！<br />
<code>emerge --ask sys-fs/e2fsprogs</code>     #ext4<br />
<code>emerge --ask sys-fs/xfsprogs</code>      #xfs<br />
<code>emerge --ask sys-fs/dosfstools</code>    #fat32<br />
<code>emerge --ask sys-fs/ntfs3g</code>        #ntfs<br />
<code>emerge --ask sys-fs/fuse-exfat</code>    #exfat<br />
<code>emerge --ask sys-fs/exfat-utils</code>   #exfat<br />
<code>emerge --ask sys-fs/btrfs-progs</code>   #btrfs</p>
<h3>配置 Linux 内核</h3>
<p>编译内核前，先安装一些必要工具<br />
<code>emerge --ask eix sudo pciutils usbutils hwinfo gentoolkit euses dev-vcs/git eselect-repository</code></p>
<p>可选工具<br />
<code>emerge --ask neovim fastfetch zsh bottom</code></p>
<p>下载安装wifi网卡和intel核显的必要驱动固件<br />
<code>emerge --ask sys-kernel/linux-firmware</code></p>
<p>安装更新Intel CPU的微码文件<br />
<code>emerge --ask sys-firmware/intel-microcode sys-apps/iucode_tool</code></p>
<p>gentoo的特色之二，就是鼓励自行配置系统内核。<br />
编译内核的方式与过程多种多样，下面我来详细说说。<br />
从以下两个方法中选一个。<br />
第一种方法：直接安装gentoo-kernel-bin软件包<br />
<code>emerge --ask gentoo-kernel-bin</code> # 此命令能自动完成内核编译，主打一个方便。但这样的缺点也很明显，没有改变任何内核设置。几乎所有功能都包含在了内核里面。一般想省时省事用这个方法比较合适。</p>
<p>第二种方法：自定义内核<br />
使用genkernel工具<br />
<code>emerge --ask gentoo-sources</code>  # 先安装内核源码<br />
<code>emerge --ask genkernel</code>  # 安装genkernel
<code>eselect kernel list</code>  # 查看内核<br />
<code>eselect kernel set X</code>  # 选择内核<br />
<code>genkernel --menuconfig kernel</code>  # 进到linux内核配置界面，genkernel默认使用gentoo-kernel的内核配置，此配置通常开箱即用，你也可以在此基础上做精简，比如精简掉你用不到的网卡、声卡、显卡等驱动和文件系统等。<br />
除了可以设为N或Y还可以将一些配置以模块形式加载（即设为M）。还请避免过度精简导致开机时内核启动卡住，这时就需要自己排除问题了。</p>
<p>**TIPS：**genkernel还有一些其他的用法，可以使用genkernel --help来查看或者去看gentoo的genkernel文档，等下就会说到如何用genkernel来配置initramfs，https://wiki.gentoo.org/wiki/Genkernel/zh-cn。</p>
<p>或者直接进linux内核目录，手动完成整个编译流程<br />
<code>emerge --ask gentoo-sources</code>  # 先安装内核源码<br />
<code>eselect kernel list</code>  # 查看当前内核<br />
<code>eselect kernel set X</code>  # 选择当前内核<br />
<code>cd /usr/src/linux</code>  #进入linux内核目录</p>
<p>(可选)如果之前已经安装过genkernel，会把linux的默认配置换成gentoo-kernel的内核配置，如果只想用linux的默认配置就执行以下命令。<br />
<code>mv .config bak.config</code> # 备份gentoo-kernel的内核配置（如果还需要此配置的话）<br />
<code>make x86_64_defconfig</code> # 使用linux默认配置<br />
使用linux默认配置通常不能开箱即用，你需要检查文件系统(vfat、ext4等)、驱动(声卡、网卡、显卡等)、init子系统(systemd or openrc)、启动项(bios or uefi)等配置是否合理开启，只有满足条件内核才能正常启动运行。</p>
<p><code>make menuconfig</code>  # 进入内核配置界面<br />
<code>make -j6</code>  #用6线程来编译内核<br />
<code>make modules_install</code>  #编译模块<br />
<code>make install</code>  #完成整个内核编译过程</p>
<p>若使用以上第二或第三种方法安装linux内核，可能还需要配置initramfs，可以用genkernel也可以用dracut，推荐用genkernel。<br />
<code>genkernel --install initramfs</code></p>
<p>使用以上三种方法的任意一种来完成内核安装操作后，一定需要配置引导加载程序。<br />
配置引导加载程序也有很多种，推荐以grub为主，https://wiki.gentoo.org/wiki/Grub。<br />
要配置grub，请执行以下命令。<br />
<code>emerge --ask sys-boot/grub</code>  # 安装grub<br />
<code>grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=Gentoo</code><br />
<code>grub-mkconfig -o /boot/grub/grub.cfg</code></p>
<h3>配置时间</h3>
<p>systemd随附了<code>timedatectl</code>命令，用于管理时区，要查看当前时区请执行该命令。<br />
之后执行<code>timedatectl list-timezones</code>命令来列出可用的时区。<br />
要更改时区（例如，更改至德国的时区），使用命令<code>timedatectl set-timezone Europe/Berlin</code>即可。</p>
<h3>配置网络</h3>
<p>emerge --ask dhcpcd<br />
如果你需要连接无线网络，我推荐iwd这个软件包。<br />
emerge --ask net-wireless/iwd<br />
具体请看官方文档，内核配置也要根据文档中的配置来更改。<br />
https://wiki.gentoo.org/wiki/Iwd</p>
<p>启动网络服务<br />
systemctl enable dhcpcd iwd</p>
<h3>配置系统用户</h3>
<p><code>visudo</code><br />
把“%wheel ALL=(ALL) ALL”这一行去掉注释</p>
<p><code>useradd -m -G users,wheel,audio,usb,video -s /bin/bash &lt;你的用户名&gt; </code><br />
<code>passwd root</code> #更改root账户密码<br />
<code>passwd &lt;你的用户名&gt;</code> #更改你自己的用户密码<br />
<code>echo &lt;主机名&gt; &gt; /etc/hostname</code></p>
<h3>最后的安装收尾和清理工作，卸载之前挂载的分区</h3>
<p><code>rm /stage3-*.tar.xz</code><br />
<code>exit</code> # 退出chroot环境<br />
<code>umount -lR /mnt/gentoo</code><br />
到此整个gentoo系统就安装结束了，重启电脑进入你的新系统好好享受吧</p>
<h3>(可选)备份gentoo</h3>
<p>第一种备份方式：以压缩包形式备份<br />
切换到根目录<br />
<code>cd /</code></p>
<p>创建备份（排除临时和虚拟文件系统），可根据自己需要来选择排除掉的文件，比如不需要排除/home中的文件就把--exclude=/home 删掉。<br />
<code>tar --create --gzip --file /backup.tar.gz --exclude=/backup.tar.gz --exclude=/home --exclude=/proc --exclude=/sys --exclude=/dev --exclude=/run --exclude=/tmp --exclude=/mnt --exclude=/media --exclude=/lost+found /</code> # 实测从刚安装结束时就压缩文件大小约为2G左右，请自行保存好该压缩包。</p>
<p>如果你要恢复该备份，请在此之前先保存好自己在该硬盘中想要保存的数据。然后用u盘进livecd系统把原本的系统盘格式化，请务必考虑清楚后再执行以下操作。<br />
进入livecd环境<br />
<code>mkfs.btrfs -f /dev/nvme0n1p1</code> #给nvme0n1p1使用btrfs文件系统<br />
<code>mkfs.vfat -F 32 /dev/nvme0n1p2</code> #给nvme0n1p2使用vfat文件系统<br />
重新挂载分区<br />
<code>mount /dev/nvme0n1p1 /mnt/gentoo</code><br />
<code>mkdir /mnt/gentoo/boot</code><br />
<code>mount /dev/nvme0n1p2 /mnt/gentoo/boot</code><br />
进到挂载nvme0n1p1的目录<br />
<code>cd /mnt/gentoo</code><br />
将备份的压缩包复制到/mnt/gentoo目录中。<br />
<code>cp &lt;你所备份的压缩包路径&gt; ./</code><br />
解压压缩包<br />
<code>tar xpvf backup.tar.gz</code><br />
复制DNS信息<br />
<code>cp --dereference /etc/resolv.conf /mnt/gentoo/etc/</code><br />
挂载系统必要环境，并进入Chroot环境<br />
<code>mount --types proc /proc /mnt/gentoo/proc</code><br />
<code>mount --rbind /sys /mnt/gentoo/sys</code><br />
<code>mount --make-rslave /mnt/gentoo/sys</code><br />
<code>mount --rbind /dev /mnt/gentoo/dev</code><br />
<code>mount --make-rslave /mnt/gentoo/dev</code><br />
<code>mount --rbind /run /mnt/gentoo/run</code><br />
<code>mount --make-rslave /mnt/gentoo/run</code><br />
<code>chroot /mnt/gentoo /bin/bash</code><br />
<code>mkdir -p /var/db/repos/gentoo</code><br />
<code>env-update</code><br />
<code>source /etc/profile</code><br />
<code>export PS1="(chroot) ${PS1}"</code></p>
<p>第二种方式：如果你和我一样都使用btrfs文件系统，可以利用btrfs特性来创建快照。<br />
备份系统<br />
<code>cd /</code> # 回到根目录<br />
<code>mkdir -p /mnt/.snapshots</code> # 创建备份目录<br />
<code>mount -o compress=zstd:3,subvol=/ /dev/nvme0n1p1 /mnt</code> # 挂载btrfs根分区<br />
<code>rm -rf /var/cache/portage/*</code> # 清理gentoo的软件包缓存（减少快照体积）<br />
<code>btrfs subvolume snapshot -r /mnt/@ /mnt/.snapshots/@-$(date +"%Y%m%d")</code> # 创建只读快照<br />
<code>umount /mnt</code> # 卸载临时挂载</p>
<p>恢复系统<br />
进入livecd环境<br />
<code>mount -o compress=zstd:3,subvol=/ /dev/nvme0n1p1 /mnt</code> # 挂载 btrfs 根分区<br />
<code>btrfs subvolume snapshot /mnt/.snapshots/@-yyyymmdd /mnt/@-restore</code> # 从快照创建临时恢复子卷<br />
修改 fstab 指向临时子卷<br />
<code>vi /etc/fstab</code> # 将"subvol=@" 改为 "subvol=@-restore"<br />
<code>cp /etc/fstab /mnt/@-restore/etc/fstab</code> # 同步修改到临时子卷的fstab<br />
<code>grub-mkconfig -o /boot/grub/grub.cfg</code> # 重建 Grub 引导配置<br />
<code>reboot</code> # 重启系统<br />
这样备份系统快速方便，过程不算太复杂。缺点就是只能在btrfs文件系统上这样备份。</p>
<p>如果你格式化或迁移了硬盘，fstab的内容也要做出相应的修改。<br />
重新更新引导加载程序<br />
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=Gentoo<br />
grub-mkconfig -o /boot/grub/grub.cfg<br />
重启后备份完成，这种备份方式兼容性强，支持各文件系统，就是压缩解压要花点时间。</p>
<p>两种备份方式也可以一起使用，最后也没什么要说的了，祝你使用gentoo愉快~</p>
<h1>参考文献</h1>
<p>Gentoo Linux amd64 Handbook： Installing Gentoo https://wiki.gentoo.org/wiki/Handbook:AMD64/Full/Installation<br />
Gentoo安装流程分享(step by step)，第一篇之基本系统的安装 https://zhuanlan.zhihu.com/p/122222365</p>
]]></content>
    <author><name>kjrin710</name></author>
    <category term="Guides"/>
  </entry>
</feed>
