Linux 安装配置 Rime 输入法指南一、概述1. 简介A. 是什么Rime（中州韵）是一个开源的中文输入法引擎，支持多种拼音方案、五笔、仓颉等输入方式。它具有高度可定制性，可满足不同用户的输入习惯。B. 为什么选择 Rime开源免费，无广告干扰支持多种输入方案，灵活切换词库可自定义，词频自动学习跨平台支持（Linux、macOS、Windows）C. 安装后能做什么使用拼音输入中文自定义词库和词频切换不同输入方案（如五笔、仓颉）调整输入法外观和行为2. 前置知识A. 必备技能基本命令行操作了解软件包管理器（apt）B. 推荐知识了解输入法框架概念（fcitx vs ibus）了解环境变量配置二、环境准备1. 系统要求Linux 发行版：Ubuntu 20.04+、Debian 10+、或其他基于 Debian 的系统桌面环境：KDE Plasma、GNOME、XFCE 等输入法框架：fcitx5（推荐）或 fcitx2. 检测现有输入法框架检查系统中已安装的输入法框架：which ibus fcitx fcitx5根据输出判断：仅显示 fcitx5：使用 fcitx5 配置仅显示 fcitx：使用 fcitx 配置显示多个：建议选择 fcitx5（现代化、性能更好）无输出：需要先安装输入法框架3. 检测桌面环境echo $XDG_CURRENT_DESKTOP常见输出：KDE：KDE Plasmaubuntu：GNOME（Ubuntu 默认）XFCE：XFCE 桌面三、安装 Rime1. 安装 fcitx5 和 RimeUbuntu/Debian 系统：sudo apt update sudo apt install fcitx5 fcitx5-rime librime-data-luna-pinyin参数说明：fcitx5：输入法框架主程序fcitx5-rime：Rime 输入法引擎的 fcitx5 适配librime-data-luna-pinyin：朙月拼音词库可选词库包：# 五笔 sudo apt install rime-data-wubi # 仓颉 sudo apt install rime-data-cangjie5 # 地球拼音 sudo apt install rime-data-terra-pinyin2. 工作原理graph TB A[用户按键] --> B[fcitx5 框架] B --> C{选择输入法} C -->|Rime| D[Rime 引擎] D --> E[词库匹配] E --> F[候选项生成] F --> G[显示候选框] G --> H[用户选择] H --> I[上屏至应用]3. 验证安装检查 Rime 组件是否安装成功：dpkg -l | grep rime应显示 fcitx5-rime 和相关词库包。四、配置环境变量1. 环境变量的作用输入法框架需要环境变量告知应用程序使用哪个输入法后端。缺少这些变量会导致输入法无法正常工作。2. 创建环境变量文件# 创建配置目录 mkdir -p ~/.config/fcitx5 # 写入环境变量 cat > ~/.config/fcitx5/env.sh << 'EOF' # Input method framework - fcitx5 export GTK_IM_MODULE=fcitx export QT_IM_MODULE=fcitx export XMODIFIERS=@im=fcitx # For Wayland export INPUT_METHOD=fcitx EOF3. 使环境变量生效添加到 shell 配置文件：# bash 用户 echo 'source ~/.config/fcitx5/env.sh' >> ~/.bashrc # zsh 用户 echo 'source ~/.config/fcitx5/env.sh' >> ~/.zshrc立即生效：source ~/.config/fcitx5/env.sh五、启用 Rime 输入法1. 方法一：使用配置工具（推荐）如果已安装配置工具：sudo apt install fcitx5-configtool fcitx5-configtool在配置工具中：点击左下角 + 按钮取消勾选 "Only Show Current Language"搜索 "Rime" 或 "Luna Pinyin"添加并提升到列表顶部2. 方法二：手动配置创建 fcitx5 配置文件：mkdir -p ~/.local/share/fcitx5 cat > ~/.local/share/fcitx5/profile.ini << 'EOF' [Groups/0] Name=Default DefaultLayout=us DefaultIM= [Groups/0/Items/0] Name=keyboard-us LangCode=en Enabled=True [Groups/0/Items/1] Name=rime LangCode=zh_CN Enabled=True [GroupOrder] 0=Default EOF六、重启输入法1. 重启 fcitx5# 停止现有 fcitx5 进程 killall fcitx5 # 启动 fcitx5 fcitx5 -d2. 配置输入法切换快捷键KDE Plasma：系统设置 → 工作区行为 → 快捷键 → 全局快捷键 → fcitx5GNOME：设置 → 键盘 → 查看和自定义快捷键 → 切换到下一个输入源默认快捷键：Ctrl + Space：切换输入法Super + Space：切换输入法（部分桌面环境）七、验证和使用1. 验证输入法打开任意文本编辑器按切换快捷键（Ctrl + Space）输入拼音，应该显示候选框2. 常用操作操作按键切换中英文Ctrl + Space 或 F4翻页. 和 ,第二候选Shift + 数字半角/全角Shift + 空格简繁切换F5 或 Ctrl + Shift + F八、高级配置1. 自定义词库用户词库位置：~/.local/share/fcitx5/rime/创建自定义词库文件：cat > ~/.local/share/fcitx5/rime/custom_words.yaml << 'EOF' --- name: custom_words version: "1.0" sort: by_weight use_preset_vocabulary: true import_tables: - luna_pinyin ... # 词库内容 ------ # 在此添加自定义词汇2. 重新部署词库修改配置后需要重新部署：rm ~/.local/share/fcitx5/rime/*.bin fcitx5-remote -r九、常见问题1. 输入法无法激活检查环境变量：echo $GTK_IM_MODULE echo $QT_IM_MODULE应输出 fcitx。如果为空，重新执行环境变量配置步骤。2. 候选框不显示检查 fcitx5 是否运行：ps aux | grep fcitx5如果没有运行，启动 fcitx5：fcitx5 -d3. 切换快捷键不生效重新登录桌面环境使环境变量完全生效。KDE 用户可能需要安装：sudo apt install fcitx5-frontend-qt5GNOME 用户可能需要安装：sudo apt install fcitx5-frontend-gtk3 fcitx5-frontend-gtk4十、卸载1. 卸载 Rimesudo apt remove fcitx5-rime librime-data-* sudo apt autoremove2. 清理配置文件rm -rf ~/.config/fcitx5 rm -rf ~/.local/share/fcitx5/rime参考资料Rime 官方文档fcitx5 官方网站
Linux 字体安装与默认字体配置一、概述1. 简介A. 是什么本文介绍在 Linux 系统上安装字体文件，并通过 fontconfig 配置系统默认字体的完整流程。B. 为什么需要Linux 系统默认缺少部分中文字体（如宋体、仿宋等）部分场景需要特定的英文字体（如 Times New Roman）统一字体设置可以提升文档阅读和编辑体验C. 学完能做什么安装用户级别的 TTF/TTC 字体文件更新系统字体缓存配置 fontconfig 设置默认字体2. 前置知识A. 必备技能基本 Linux 命令操作了解目录结构概念B. 推荐知识了解 XML 配置文件格式二、环境准备1. 系统要求Linux 发行版：Ubuntu、Debian、Kubuntu 等已安装 fontconfig 包（默认通常已安装）2. 字体文件中文字体：TTF 或 TTC 格式英文字体：TTF 格式三、核心概念1. 基本术语fontconfig：Linux 系统的字体配置框架fc-cache：字体缓存更新工具fc-list：字体列表查询工具fc-match：字体匹配查询工具2. 字体目录结构graph TD A[字体目录] --> B[用户级别] A --> C[系统级别] B --> D[~/.local/share/fonts] C --> E[/usr/share/fonts] D --> F[chinese] D --> G[english] E --> H[truetype] E --> I[opentype]3. 工作原理fontconfig 通过以下步骤管理字体：扫描字体目录构建字体缓存根据配置文件匹配字体返回最佳匹配结果四、安装步骤1. 创建字体目录mkdir -p ~/.local/share/fonts/chinese mkdir -p ~/.local/share/fonts/english2. 复制字体文件将中文字体复制到 chinese 目录：cp /path/to/simsun.ttc ~/.local/share/fonts/chinese/ cp /path/to/simhei.ttf ~/.local/share/fonts/chinese/ cp /path/to/simfang.ttf ~/.local/share/fonts/chinese/将英文字体复制到 english 目录：cp /path/to/times.ttf ~/.local/share/fonts/english/3. 更新字体缓存fc-cache -fv ~/.local/share/fonts/成功输出示例：/home/lab/.local/share/fonts/chinese: caching, new cache contents: 6 fonts, 0 dirs /home/lab/.local/share/fonts/english: caching, new cache contents: 1 fonts, 0 dirs fc-cache: succeeded五、配置默认字体1. 创建配置文件mkdir -p ~/.config/fontconfig2. 编辑配置文件创建 ~/.config/fontconfig/fonts.conf 文件：<?xml version="1.0"?> <fontconfig> <alias> <family>serif</family> <prefer> <family>Times New Roman</family> </prefer> </alias> <match> <test name="lang"> <string>zh-cn</string> </test> <test name="family"> <string>serif</string> </test> <edit name="family" mode="prepend" binding="strong"> <string>SimSun</string> </edit> </match> </fontconfig>3. 配置说明fontconfig 配置文件结构：graph LR A[fontconfig] --> B[alias 别名] A --> C[match 匹配规则] B --> D[family 字体族] B --> E[prefer 优先级] C --> F[test 条件] C --> G[edit 编辑动作]六、验证安装1. 查看已安装字体# 查看所有中文字体 fc-list :lang=zh-cn # 查看特定字体 fc-list | grep -i "simsun" fc-list | grep -i "times new roman"2. 验证默认字体# 查看默认 serif 字体 fc-match serif # 查看中文环境下的默认字体 fc-match "sans-serif" :lang=zh-cn七、常用命令1. 字体管理命令命令功能fc-cache更新字体缓存fc-list列出已安装字体fc-match查询字体匹配结果fc-cat显示字体缓存内容fc-pattern显示字体匹配模式2. 常用参数-f：自定义输出格式-v：显示详细信息:lang=xx：指定语言环境八、常见问题1. 字体未生效问题症状安装字体后，应用程序仍未显示新字体解决方法确认字体缓存已更新重启应用程序检查字体文件是否完整2. 配置文件语法错误问题症状fontconfig 无法读取配置文件解决方法使用 XML 验证工具检查语法：xmllint --noout ~/.config/fontconfig/fonts.conf3. 权限问题问题症状无法安装字体到系统目录解决方法使用用户级别目录 ~/.local/share/fonts/ 无需 sudo 权限参考资料Fontconfig User DocumentationLinux 字体配置指南
Mac Pro 垃圾桶安装 Ubuntu 24.04/Kubuntu 24.04 GPU 配置指南
Mac Pro 垃圾桶安装 Ubuntu 24.04/Kubuntu 24.04 GPU 配置指南一、概述1. 简介A. 硬件背景Mac Pro 垃圾桶（Late 2013/2014，代号 MacPro6,1）是苹果设计的经典工作站，配备双 AMD FirePro D500 显卡（基于 Tahiti LE 核心）。这款机器至今仍有不少用户将其改造为 Linux 工作站。B. 为何需要配置Ubuntu 24.04/Kubuntu 24.04 使用较新的内核（6.x 系列），对 AMD 旧架构 GPU 的驱动支持存在一些兼容性问题。默认配置可能导致：偶发性黑屏PCIe 总线错误驱动加载异常C. 配置目标确保双 GPU 正常工作使用稳定的 radeon 驱动优化电源管理以减少错误提供自动化配置脚本2. 前置知识A. 必备技能基本 Linux 命令操作能够使用文本编辑器（nano/vim）了解如何重启系统和进入 GRUB 菜单B. 硬件信息组件规格GPU双 AMD FirePro D500 (Tahiti LE)架构CIK/SI 系列显存3GB GDDR5 × 2二、问题分析1. 驱动选择困境AMD 对旧架构 GPU 有两套驱动：graph TB A[AMD GPU 驱动] --> B[radeon] A --> C[amdgpu] B --> D[传统驱动] B --> E[稳定但功能旧] C --> F[新一代驱动] C --> G[功能完善但支持有限] H[Tahiti 架构] --> I[默认使用 radeon] I --> J[amdgpu 支持不完善]2. 遇到的问题A. amdgpu 驱动尝试失败在 6.17 内核上尝试切换到 amdgpu 驱动时：amdgpu 0000:02:00.0: probe with driver amdgpu failed with error -22错误代码 -22 (EINVAL) 表示驱动初始化参数无效，amdgpu 对 Tahiti 的支持仍处于实验阶段。B. PCIe 总线错误使用 radeon 驱动时，系统日志中可能出现：radeon 0000:06:00.0: PCIe Bus Error: severity=Correctable, type=Data Link Layer这可能导致长期使用后出现黑屏。C. 内核参数冲突GRUB 配置中的参数设置不当可能导致：radeon.cik_support=0 阻止了驱动加载amdgpu 参数与实际硬件不匹配三、解决方案1. 驱动策略经过测试，在 Ubuntu 24.04/Kubuntu 24.04 上：推荐使用 radeon 驱动：稳定且功能完整不推荐 amdgpu：对 Tahiti 支持不完善，可能导致黑屏2. 配置参数说明A. radeon 驱动参数options radeon si_support=1 # 启用 SI 架构支持 options radeon cik_support=1 # 启用 CIK 架构支持 options radeon audio=1 # 启用 HDMI 音频 options radeon dynclks=1 # 动态时钟调节 options radeon rlc_enable=1 # 启用 RLC 固件B. GRUB 内核参数radeon.si_support=1 # 启用 SI 支持 radeon.cik_support=1 # 启用 CIK 支持 intel_iommu=off # 禁用 Intel IOMMU（可能影响 GPU） pci=realloc # PCI 资源重新分配四、自动化配置脚本1. 一键配置脚本将以下脚本保存为 setup-macpro-gpu.sh：#!/bin/bash # Mac Pro 垃圾桶 Ubuntu 24.04/Kubuntu 24.04 GPU 配置脚本 # 适用于双 AMD FirePro D500 (Tahiti LE) set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BACKUP_DIR="$SCRIPT_DIR/backups-$(date +%Y%m%d-%H%M%S)" LOG_FILE="$SCRIPT_DIR/setup-gpu.log" # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # 日志函数 log() { echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE" } warn() { echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1" | tee -a "$LOG_FILE" } error() { echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" | tee -a "$LOG_FILE" } # 检查是否为 root check_root() { if [ "$EUID" -ne 0 ]; then error "请使用 sudo 运行此脚本" exit 1 fi } # 检测 GPU detect_gpu() { log "检测 GPU 设备..." GPU_INFO=$(lspci -nn | grep -i "vga.*amd") if echo "$GPU_INFO" | grep -qi "tahiti\|firepro.*d500\|radeon.*hd.*7870"; then log "检测到 FirePro D500 (Tahiti) GPU" return 0 else warn "未检测到 FirePro D500 GPU" warn "检测到的 GPU: $GPU_INFO" read -p "是否继续配置? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi fi } # 备份配置文件 backup_configs() { log "备份配置文件到 $BACKUP_DIR" mkdir -p "$BACKUP_DIR" [ -f /etc/default/grub ] && cp /etc/default/grub "$BACKUP_DIR/" [ -f /etc/modprobe.d/amd-gpu.conf ] && cp /etc/modprobe.d/amd-gpu.conf "$BACKUP_DIR/" 2>/dev/null || true log "备份完成" } # 配置 modprobe configure_modprobe() { log "配置 modprobe..." cat > /etc/modprobe.d/amd-gpu.conf << 'EOF' # AMD GPU Driver Configuration for FirePro D500 (Tahiti) # Mac Pro 垃圾桶 Ubuntu 24.04/Kubuntu 24.04 # 配置 radeon 驱动以获得最佳稳定性 options radeon si_support=1 options radeon cik_support=1 options radeon audio=1 options radeon dynclks=1 options radeon rlc_enable=1 EOF log "modprobe 配置完成" } # 配置 GRUB configure_grub() { log "配置 GRUB 内核参数..." # 读取当前配置 CURRENT_GRUB=$(grep "^GRUB_CMDLINE_LINUX_DEFAULT=" /etc/default/grub | sed "s/^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"$/\1/") # 移除旧的 GPU 相关参数 NEW_GRUB=$(echo "$CURRENT_GRUB" | sed -E 's/radeon\.(si|cik)_support=[^ ]+ //g') NEW_GRUB=$(echo "$NEW_GRUB" | sed -E 's/amdgpu\.(si|cik)_support=[^ ]+ //g') NEW_GRUB=$(echo "$NEW_GRUB" | sed -E 's/amdgpu\.dc=[^ ]+ //g') # 添加新参数 NEW_GRUB="$NEW_GRUB radeon.si_support=1 radeon.cik_support=1" # 移除多余空格 NEW_GRUB=$(echo "$NEW_GRUB" | sed 's/ */ /g' | sed 's/^ //;s/ $//') # 更新配置 sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"$NEW_GRUB\"|" /etc/default/grub log "GRUB 配置已更新" log "新参数: radeon.si_support=1 radeon.cik_support=1" } # 更新 initramfs update_initramfs() { log "更新 initramfs..." update-initramfs -u -k all log "initramfs 更新完成" } # 更新 GRUB update_grub() { log "更新 GRUB..." update-grub log "GRUB 更新完成" } # 显示结果 show_result() { log "" log "==========================================" log " 配置完成！" log "==========================================" log "" log "请执行以下操作：" log " 1. 重启系统: sudo reboot" log " 2. 重启后验证 GPU 状态" log "" log "验证命令：" log " lsmod | grep radeon # 检查驱动是否加载" log " ls -la /sys/class/drm/card*/device/driver # 检查 GPU 绑定" log " glxinfo | grep 'OpenGL renderer' # 检查 OpenGL 状态" log "" log "如果出现问题，可以使用备份文件恢复：" log " 备份位置: $BACKUP_DIR" log "" } # 主函数 main() { log "==========================================" log " Mac Pro 垃圾桶 GPU 配置脚本" log "==========================================" log "" check_root detect_gpu backup_configs configure_modprobe configure_grub update_initramfs update_grub show_result } # 执行主函数 main2. 脚本使用方法A. 下载并运行# 创建脚本文件 nano ~/setup-macpro-gpu.sh # 粘贴脚本内容后保存，然后赋予执行权限 chmod +x ~/setup-macpro-gpu.sh # 运行脚本 sudo ~/setup-macpro-gpu.shB. 重启验证sudo reboot重启后运行验证命令：# 检查驱动模块 lsmod | grep radeon # 检查 GPU 绑定 ls -la /sys/class/drm/card*/device/driver # 检查 OpenGL 渲染器 glxinfo | grep "OpenGL renderer" # 检查 PCIe 错误 sudo dmesg | grep -i "pcie.*error"五、手动配置步骤如果自动化脚本无法运行，可以按照以下步骤手动配置：1. 配置 modprobesudo nano /etc/modprobe.d/amd-gpu.conf添加以下内容：# AMD GPU Driver Configuration for FirePro D500 (Tahiti) options radeon si_support=1 options radeon cik_support=1 options radeon audio=1 options radeon dynclks=1 options radeon rlc_enable=12. 配置 GRUBsudo nano /etc/default/grub修改 GRUB_CMDLINE_LINUX_DEFAULT 行：GRUB_CMDLINE_LINUX_DEFAULT='quiet splash radeon.si_support=1 radeon.cik_support=1 intel_iommu=off pci=realloc'3. 更新系统# 更新 initramfs sudo update-initramfs -u -k all # 更新 GRUB sudo update-grub # 重启 sudo reboot六、故障排查1. 常见问题A. 黑屏无法进入系统解决方法：重启时按住 Shift 键进入 GRUB 菜单选择 Advanced options选择带 recovery mode 的内核在 recovery menu 中选择 root挂载文件系统：mount -o remount,rw /编辑 GRUB 配置：nano /etc/default/grub在内核参数中添加 nomodeset更新 GRUB：update-grub重启后重新配置B. OpenGL 显示软件渲染检查：glxinfo | grep "OpenGL renderer"如果显示 llvmpipe 而不是 TAHITI，说明 GPU 硬件加速未启用。解决方法：# 检查驱动模块 lsmod | grep radeon # 检查设备绑定 ls -la /sys/class/drm/card*/device/driverC. 持续出现 PCIe 错误解决方法：检查 GPU 温度是否正常尝试降级到 LTS 内核（如 6.5 或 5.15）考虑清理 GPU 散热器灰尘2. 日志检查# 检查 GPU 相关日志 sudo dmesg | grep -i radeon | tail -20 # 检查 PCIe 错误 sudo dmesg | grep -i "pcie.*error" # 检查系统日志 journalctl --since "1 hour ago" | grep -i gpu七、性能优化建议1. 电源管理# 查看 GPU 当前性能级别 cat /sys/class/drm/card1/device/power_dpm_state # 设置为平衡模式 sudo echo auto > /sys/class/drm/card1/device/power_dpm_state2. 禁用未使用的 GPU如果只使用一个显示器，可以禁用第二个 GPU 以节省功耗：# 注意：这需要根据具体连接情况调整 echo OFF > /sys/class/drm/card1/device/DP-1/dpms3. 内核选择如果遇到持续问题，可以尝试安装较旧的 LTS 内核：# 查看可用内核 apt search linux-image # 安装 LTS 内核 sudo apt install linux-image-6.5.0-generic linux-headers-6.5.0-generic八、参考资料AMDGPU Linux Driver DocumentationUbuntu Wiki - AMDGPUArch Wiki - AMDGPUMac Pro Linux
Mac Pro 垃圾桶 Kubuntu 24.04 显卡黑屏问题诊断与修复一、事件概述1. 事件背景用户在 Mac Pro 垃圾桶（Late 2013/2014）上安装 Kubuntu 24.04 系统，配备双 AMD FirePro D500 显卡。系统运行基本正常，但偶尔在长时间使用后出现黑屏现象。2. 影响范围A. 影响用户数单用户环境，个人工作站B. 影响时长间歇性发生，无固定时间模式，主要出现在长时间使用后C. 影响功能显示输出中断，需重启系统恢复3. 严重程度P2 级问题（影响用户体验，但可临时恢复）二、事件时间线1. 问题发现（时间：用户报告时）A. 现象描述系统运行正常，偶尔出现黑屏无明显预兆，可能发生在长时间使用后重启后可恢复正常B. 初步检查系统为 Kubuntu 24.04，内核版本 6.17.0-19-generic硬件为双 AMD FirePro D500（Tahiti LE 架构）OpenGL 渲染正常工作2. 系统诊断（时间：诊断阶段）A. 发现途径通过系统性调试流程，收集系统证据B. 诊断过程检查硬件状态：lspci 显示双 GPU 设备正常识别温度传感器显示 51-58°C，温度正常OpenGL 渲染器显示 TAHITI (radeonsi)，工作正常检查驱动状态：两块 GPU 都绑定到 radeon 驱动内核参数设置了 amdgpu.cik_support=1，但未生效amdgpu 模块已加载但引用数为 0（未使用）radeon 模块有 93 个引用（正在使用）检查系统日志：发现频繁的 PCIe Bus Error错误信息：radeon 0000:06:00.0: PCIe Bus Error: severity=Correctable, type=Data Link Layer错误代码：00000040（TLP 错误）3. 根因确认（时间：分析阶段）A. 问题定位虽然内核参数设置了 amdgpu.cik_support=1，但 radeon 模块仍在先加载并接管 GPU 设备。旧的 radeon 驱动对 Tahiti（CIK）架构的 PCIe 处理不如新的 amdgpu 驱动完善，导致频繁的 PCIe 总线错误。这些错误长期累积可能触发黑屏问题。B. 证据链graph LR A[内核参数设置] -->|期望| B[amdgpu 加载] C[radeon 模块] -->|实际| D[先加载并绑定 GPU] D --> E[旧驱动 PCIe 处理不完善] E --> F[频繁 PCIe 错误] F --> G[长期累积导致黑屏]三、问题分析1. 直接原因双 AMD FirePro D500 GPU 使用的是旧的 radeon 驱动，而不是更新的 amdgpu 驱动。2. 根本原因（5 Whys 分析）A. 为什么使用旧驱动？尽管内核参数设置了 amdgpu.cik_support=1，但模块加载顺序导致 radeon 先加载并绑定设备。B. 为什么 radeon 先加载？modprobe 配置中没有明确阻止 radeon 加载，模块在 initramfs 阶段就决定了加载顺序。C. 为什么内核参数未生效？内核参数可以启用 amdgpu 对 CIK 的支持，但不能阻止 radeon 同时加载并抢先绑定设备。D. 为什么会导致黑屏？radeon 驱动对 Tahiti 架构的 PCIe 错误处理不如 amdgpu 完善，频繁的总线错误累积可能导致 GPU 挂起或显示中断。E. 深层反思CIK（Tahiti）架构是 AMD GPU 的旧架构，amdgpu 驱动从 Linux 4.15 开始添加对其支持，但默认行为仍倾向使用 radeon。需要明确配置才能强制使用 amdgpu。3. 技术背景Mac Pro 垃圾桶（2013/2014）配备的 FirePro D500 基于 AMD Tahiti LE 核心（Radeon HD 7870 XT），属于 CIK（Core Islands Kitchen）架构系列。这是 AMD GPU 架构发展中的一个重要节点：radeon 驱动：传统驱动，功能完善但更新缓慢amdgpu 驱动：新一代驱动，更好的电源管理和错误处理四、解决方案1. 临时方案A. 实施措施无需临时方案，可直接进行永久修复B. 风险评估驱动切换有风险，需准备回滚方案2. 永久方案A. 改进措施创建 modprobe 配置文件，强制使用 amdgpu 驱动：创建 /etc/modprobe.d/amd-gpu.conf添加 blacklist radeon 阻止旧驱动加载配置 amdgpu 选项启用 CIK 支持更新 initramfs 使配置生效重启系统验证B. 实施步骤步骤 1：备份现有配置sudo cp /etc/default/grub /etc/default/grub.backup-$(date +%Y%m%d) sudo cp /etc/modprobe.d/blacklist.conf /etc/modprobe.d/blacklist.conf.backup-$(date +%Y%m%d)步骤 2：创建驱动配置文件sudo nano /etc/modprobe.d/amd-gpu.conf文件内容：# AMD GPU Driver Configuration # Force amdgpu for CIK (Tahiti) GPUs instead of legacy radeon driver # Blacklist legacy radeon driver blacklist radeon blacklist radeonfb # Options for amdgpu to enable CIK support options amdgpu cik_support=1 options amdgpu dc=1 # Disable radeon CIK support options radeon cik_support=0步骤 3：更新 initramfssudo update-initramfs -u -k all步骤 4：重启系统sudo rebootC. 验证方法重启后运行验证脚本检查驱动状态：bash /tmp/verify-amdgpu.sh预期结果：两块 GPU 都使用 amdgpu 驱动lsmod 显示 amdgpu 有引用计数日志中 PCIe 错误减少或消失3. 回滚方案A. 回滚条件如果切换后出现无法启动、显示异常等问题B. 回滚步骤# 删除配置文件 sudo rm /etc/modprobe.d/amd-gpu.conf # 更新 initramfs sudo update-initramfs -u -k all # 重启系统 sudo reboot4. 预防措施定期检查系统日志中的 PCIe 错误监控 GPU 温度和负载保持内核和驱动更新五、经验总结1. 诊断关键点系统日志是问题诊断的重要线索驱动状态检查需要同时看模块加载和设备绑定旧硬件在新系统上可能需要手动配置驱动2. 技术要点内核参数和 modprobe 配置需要配合使用模块加载顺序在 initramfs 阶段决定CIK 架构的 AMD GPU 在新系统上应使用 amdgpu 驱动3. 调试方法遵循系统性调试原则：先收集证据，再分析根因使用 lspci、lsmod、journalctl 等工具全面检查从硬件到驱动，从日志到配置，层层递进4. AMD GPU 驱动选择建议架构系列推荐驱动备注CIK（Tahiti）amdgpu需要配置启用VI（Polaris）amdgpu默认支持Vega 及更新amdgpu默认支持六、参考资料AMDGPU Linux Driver DocumentationUbuntu Wiki - AMDGPUArch Wiki - AMDGPU
Rime 输入法在 Kubuntu 24.04 上的安装与配置一、概述1. 简介A. 是什么Rime（中州韵输入法引擎）是一款跨平台的输入法框架，支持拼音、双拼、五笔等多种输入方案。它以高度可定制和优秀的中文输入体验著称。B. 为什么选择 Rime开源免费，无广告干扰支持多种输入方案，可高度定制跨平台支持，配置可在不同系统间同步词库丰富，输入准确率高C. 学完能做什么在 Kubuntu 系统上安装并使用 Rime 输入法掌握 Fcitx5 输入法框架的配置方法自定义 Rime 输入方案和词库2. 前置知识A. 必备技能基本 Linux 命令行操作了解软件包管理器 apt 的使用B. 推荐知识了解输入法框架概念（IBus、Fcitx 等）了解 Linux 环境变量配置二、环境准备1. 系统要求操作系统：Kubuntu 24.04 或其他 Ubuntu 24.04 衍生版本桌面环境：KDE Plasma权限：sudo 访问权限用于安装软件包2. 输入法框架选择Linux 上的输入法框架主要有 IBus 和 Fcitx5 两种。对于 Rime 输入法，推荐使用 Fcitx5，原因如下：输入法框架优点缺点推荐度IBus系统默认集成对 Rime 支持一般，配置复杂一般Fcitx5轻量高效，Rime 支持完善需手动安装强烈推荐3. 安装步骤A. 更新软件包索引sudo apt updateB. 安装 Fcitx5 和 Rimesudo apt install -y fcitx5 fcitx5-rime fcitx5-chinese-addons fcitx5-frontend-gtk3 fcitx5-frontend-gtk4 fcitx5-frontend-qt5各组件说明：fcitx5：核心框架fcitx5-rime：Rime 输入法引擎fcitx5-chinese-addons：中文相关增强功能fcitx5-frontend-*：各应用的前端支持库C. 安装配置工具（可选但推荐）sudo apt install -y fcitx5-config-qt4. 验证安装# 检查 Fcitx5 版本 fcitx5 --version # 检查 Rime 是否安装 dpkg -l | grep fcitx5-rime三、核心概念1. 基本术语Fcitx5：Free Chinese Input Toy for X，新一代输入法框架Rime：输入法引擎，负责将拼音转换为汉字输入法前端：Fcitx5 与应用程序之间的桥梁（GTK/Qt 前端）输入方案：Rime 的输入规则配置，如朙月拼音、地球拼音等2. 工作原理graph TB A[用户按键] --> B[Fcitx5 框架] B --> C{输入法类型} C -->|英文| D[直接输出] C -->|中文| E[Rime 引擎] E --> F[词库匹配] F --> G[候选词生成] G --> H[前端显示] H --> I[用户选择] I --> J[应用程序]3. 配置架构graph LR A[环境变量配置] --> B[Fcitx5 配置] B --> C[Rime 方案配置] C --> D[用户自定义] E[~/.config/environment.d] --> A F[~/.config/fcitx5] --> B G[~/.local/share/fcitx5/rime] --> C四、快速上手1. 环境变量配置A. 创建环境变量文件mkdir -p ~/.config/environment.d cat > ~/.config/environment.d/im.conf << 'EOF' GTK_IM_MODULE=fcitx QT_IM_MODULE=fcitx XMODIFIERS=@im=fcitx INPUT_METHOD=fcitx EOFB. 添加到 bashrc（当前会话生效）cat >> ~/.bashrc << 'EOF' # Fcitx5 Input Method export GTK_IM_MODULE=fcitx export QT_IM_MODULE=fcitx export XMODIFIERS=@im=fcitx EOF # 立即生效 source ~/.bashrcC. 配置自动启动mkdir -p ~/.config/autostart cat > ~/.config/autostart/fcitx5.desktop << 'EOF' [Desktop Entry] Name=Fcitx 5 Comment=Input Method Framework Exec=fcitx5 Icon=fcitx Type=Application Categories=System;Utility; X-GNOME-Autostart-enabled=true X-KDE-autostart-after=panel EOF2. 启动 Fcitx5A. 停止旧的输入法框架pkill ibusB. 启动 Fcitx5 守护进程fcitx5 -dC. 验证运行状态pgrep -a fcitx5 fcitx5-remote -n3. 配置 Rime 输入法A. 使用图形配置工具（推荐）fcitx5-config-qt在打开的配置窗口中：点击左下角「添加输入法」按钮取消勾选「仅显示当前语言」搜索「Rime」添加「Rime」输入法可将 Rime 拖到列表顶部设为默认B. 命令行配置方式# 创建 Rime 配置目录 mkdir -p ~/.local/share/fcitx5/rime # 设置默认输入方案 cat > ~/.local/share/fcitx5/rime/default.yaml << 'EOF' schema_list: - schema: luna_pinyin # 朙月拼音 - schema: luna_pinyin_simp # 朙月拼音简化字 EOF4. 切换输入法配置完成后，使用以下快捷键切换：快捷键功能Ctrl + Space切换输入法Super + Space切换输入法组Shift中英文切换Ctrl + ~重新部署 Rime 配置五、进阶内容1. 常用配置A. 设置默认输入法在 ~/.config/fcitx5/profile 中设置：[InputMethod/Groups/0] DefaultInputMethod=rimeB. 自定义快捷键编辑 ~/.config/fcitx5/profile：[Hotkey/TriggerKeys] 0=Control+space 1=Shift+Shift_L2. 输入方案定制Rime 支持丰富的输入方案，常用的包括：方案名称说明luna_pinyin朙月拼音，默认方案luna_pinyin_simp朙月拼音简化字terra_pinyin地球拼音，支持 Emojidouble_pinyin_flypy小鹤双拼wubi86五笔 86 版创建自定义方案：# 编辑用户配置 vim ~/.local/share/fcitx5/rime/user.yaml # 修改后重新部署 fcitx5-remote -r # 或按 Ctrl + ~ 重新部署3. 词库管理A. 添加自定义词库下载词库文件（如 my_dict.yaml）放入 ~/.local/share/fcitx5/rime/ 目录在对应方案文件中引用： import_tables: - my_dict重新部署（Ctrl + ~）B. 词库同步Rime 配置和词库可以跨平台同步，同步 ~/.local/share/fcitx5/rime/ 目录即可。六、常见问题1. 安装问题Q：apt 无法找到 fcitx5-rime 包A：确保软件包索引已更新，并启用 universe 仓库：sudo apt update sudo add-apt-repository universe sudo apt updateQ：安装后无法启动 Fcitx5A：检查是否有冲突的输入法框架：pkill ibus pkill fcitx fcitx5 -d2. 配置问题Q：环境变量不生效A：环境变量修改需要重新登录才能完全生效。当前会话可手动设置：export GTK_IM_MODULE=fcitx export QT_IM_MODULE=fcitx export XMODIFIERS=@im=fcitx fcitx5-remote -rQ：Rime 不在输入法列表中A：确保已安装 fcitx5-rime，并重启 Fcitx5：fcitx5-remote -r3. 使用问题Q：无法切换出中文输入A：检查以下几点：Fcitx5 是否正在运行：pgrep fcitx5Rime 是否已添加到输入法列表：使用 fcitx5-config-qt 检查环境变量是否正确：env | grep IM_MODULEQ：候选词显示异常A：尝试重新部署 Rime：# 按 Ctrl + ~ 重新部署 # 或删除编译文件重启 rm ~/.local/share/fcitx5/rime/*.bin fcitx5-remote -rQ：输入卡顿或延迟A：可能是词库过大导致，尝试：清理不必要的词库使用精简版输入方案检查系统资源占用七、实用技巧1. 快速定位配置# Fcitx5 配置目录 ~/.config/fcitx5/ # Rime 用户配置目录 ~/.local/share/fcitx5/rime/ # 环境变量配置 ~/.config/environment.d/im.conf2. 调试命令# 查看当前输入法 fcitx5-remote -n # 切换到指定输入法 fcitx5-remote -s rime # 查看可用输入法 dbus-send --session --print-reply \ --dest=org.fcitx.Fcitx5 /controller \ org.fcitx.Fcitx.Controller1.AvailableInputMethods # 查看 Fcitx5 日志 fcitx5 -d --verbose3. 性能优化禁用不需要的输入法前端使用精简词库定期清理用户配置中的冗余数据参考资料Fcitx5 官方文档Rime 官方网站Rime 配置指南Kubuntu 官方文档
Linux 应用开发基础教程一、概述1. 简介A. 是什么《Linux Application Development By Example - The Fundamental APIs》是由 Arnold Robbins 编写的 Linux 应用程序开发教程书籍，第二版于 2026 年出版。本书通过大量示例代码，系统介绍 Linux 系统编程的核心 API 和开发技巧。B. 为什么学掌握 Linux 系统编程基础，理解操作系统工作原理学习 POSIX 标准 API，提升跨平台开发能力通过实例代码快速掌握复杂的系统调用概念培养底层思维，为学习高级框架打下坚实基础C. 学完能做什么开发 Linux 命令行工具和系统程序处理文件 I/O、进程管理、信号处理等系统级任务进行网络编程和国际化应用开发使用调试工具分析和修复程序问题2. 前置知识A. 必备技能C 语言基础：指针、结构体、内存管理基本 Linux 操作：命令行使用、文件系统概念编译工具使用：gcc、makeB. 推荐知识操作系统基础概念：进程、线程、虚拟内存POSIX 标准了解Git 版本控制二、书籍结构1. 内容组织本书共 17 章，涵盖 Linux 应用开发的各个方面：mindmap root((Linux 应用开发)) 基础入门 第1章 简介 第2章 命令行 第3章 内存 文件操作 第4章 文件IO 第5章 文件信息 第7章 ls 实现 进程管理 第9章 进程 第10章 信号 第12章 资源限制 系统功能 第6章 通用工具1 第8章 挂载 第13章 通用工具2 高级主题 第14章 网络 第15章 国际化 第16章 扩展属性 第17章 调试2. 章节概览章节目录主题第 1 章ch-01-intro入门示例，数学计算程序第 2 章ch-02-cmdline命令行参数处理，环境变量第 3 章ch-03-memory动态内存分配，地址空间第 4 章ch-04-fileio文件 I/O，系统调用与库函数第 5 章ch-05-fileinfo文件元数据，stat 系统调用第 6 章ch-06-general1通用工具：时间、用户信息第 7 章ch-07-ls实现 ls 命令第 8 章ch-08-mounting文件系统挂载第 9 章ch-09-processes进程创建与管理第 10 章ch-10-signals信号处理第 12 章ch-12-limits系统资源限制第 13 章ch-13-general2更多通用工具第 14 章ch-14-networking网络编程基础第 15 章ch-15-i18n国际化与本地化第 16 章ch-16-extended扩展属性第 17 章ch-17-debugging调试技巧与工具三、核心概念1. 系统调用与库函数Linux 编程中区分两类函数：A. 系统调用直接进入内核态执行开销较大，需要上下文切换提供核心功能：文件操作、进程管理、网络通信B. 库函数在用户态执行通常封装系统调用，提供更友好的接口标准 C 库函数：printf、malloc、fopengraph TB A[应用程序] --> B{函数类型} B -->|库函数| C[glibc 等] B -->|系统调用| D[内核] C --> D D --> E[硬件资源]2. Linux 编程模型A. 一切皆文件普通文件、目录、设备、套接字都通过文件描述符访问标准 I/O：stdin（0）、stdout（1）、stderr（2）B. 进程模型进程是资源分配的基本单位fork + exec 创建新进程父子进程关系与等待机制C. 权限模型用户 ID 和组 ID文件权限：rwx 权限位setuid/setgid 机制四、快速上手1. 获取代码克隆本书的代码仓库：git clone https://github.com/arnoldrobbins/LinuxByExample-2e.git cd LinuxByExample-2e2. 编译示例各章节目录包含独立的示例程序，使用 gcc 编译：cd ch-01-intro gcc -o sindegrees ch-intro-sindegrees.c -lm ./sindegrees3. 代码风格说明命名规范：ch-<章节名>-<功能描述>.c头文件：ch-<章节名>-<功能描述>.h测试程序：ch-<章节名>-<功能>-test*.c脚本文件：功能描述.sh五、重点章节解析1. 第 1 章：入门示例A. 数学计算程序该章实现一个角度与弧度转换的程序，展示基本的 C 程序结构和数学库使用。核心代码结构：主程序：ch-intro-sindegrees.c头文件：ch-intro-sindegrees.h测试程序：多个测试版本2. 第 2 章：命令行处理A. main 函数参数int main(int argc, char *argv[])argc：参数个数argv：参数值数组argv[0]：程序名称argv[1] 到 argv[argc-1]：实际参数B. 环境变量extern char **environ;访问环境变量的两种方式：全局变量 environgetenv/setenv 函数示例程序：ch-cmdline-printenv.c（实现 printenv 命令）3. 第 3 章：内存管理A. 动态内存分配void *malloc(size_t size); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); void free(void *ptr);B. 内存地址程序地址空间布局：代码段只读数据段全局数据段堆（向上增长）栈（向下增长）graph TB subgraph "进程地址空间" A[高地址] B[栈] C[空闲区域] D[堆] E[未初始化数据 BSS] F[已初始化数据] G[代码段] H[低地址] end B -->|向下增长| C D -->|向上增长| C4. 第 4 章：文件 I/OA. 系统调用int open(const char *pathname, int flags, mode_t mode); ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); int close(int fd);B. 库函数FILE *fopen(const char *path, const char *mode); size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); int fclose(FILE *stream);C. 选择建议场景推荐使用原因二进制文件系统调用精确控制文本文件库函数缓冲提高效率设备文件系统调用直接访问普通应用库函数可移植性好5. 第 9 章：进程管理A. 创建进程sequenceDiagram participant P as 父进程 participant K as 内核 participant C as 子进程 P->>K: fork() K->>C: 创建子进程 C-->>P: 返回子进程 PID P->>P: 父进程中返回子进程 PID C->>C: 子进程中返回 0 C->>K: exec(program) K->>C: 加载新程序B. fork 函数pid_t fork(void);调用一次，返回两次父进程中返回子进程 PID子进程中返回 0失败返回 -1C. exec 函数族int execl(const char *path, const char *arg, ...); int execv(const char *path, char *const argv[]); int execle(const char *path, const char *arg, ...); int execve(const char *path, char *const argv[], char *const envp[]);替换当前进程映像为新程序。6. 第 10 章：信号处理A. 常见信号信号值默认动作说明SIGINT2终止Ctrl+CSIGQUIT3终止+coreCtrl+\SIGKILL9终止强制杀死SIGTERM15终止终止信号SIGCHLD17忽略子进程状态改变B. 信号处理typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);处理方式：SIG_DFL：默认处理SIG_IGN：忽略信号自定义函数：捕获信号7. 第 14 章：网络编程A. 套接字 APIint socket(int domain, int type, int protocol); int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); int listen(int sockfd, int backlog); int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);B. 客户端-服务器模型sequenceDiagram participant C as 客户端 participant S as 服务器 C->>S: socket() S->>S: socket() S->>S: bind() S->>S: listen() C->>S: connect() S->>S: accept() C-->>S: 请求数据 S-->>C: 响应数据 C->>C: close() S->>S: close()六、开发工具1. 编译工具A. gcc# 基本编译 gcc -o program program.c # 启用所有警告 gcc -Wall -Wextra -o program program.c # 链接数学库 gcc -o program program.c -lm # 生成调试信息 gcc -g -o program program.c # 优化编译 gcc -O2 -o program program.cB. make自动化构建工具，使用 Makefile 管理编译规则。2. 调试工具A. gdb# 启动调试 gdb ./program # 常用命令 break main # 设置断点 run # 运行程序 next # 单步执行 print variable # 打印变量 backtrace # 查看调用栈B. strace跟踪系统调用：strace ./programC. ltrace跟踪库函数调用：ltrace ./program七、最佳实践1. 错误处理// 检查系统调用返回值 if (fd < 0) { perror("open"); exit(EXIT_FAILURE); } // 检查库函数返回值 if ((ptr = malloc(size)) == NULL) { fprintf(stderr, "malloc failed\n"); exit(EXIT_FAILURE); }2. 资源管理// 确保释放资源 FILE *fp = fopen("file.txt", "r"); if (fp == NULL) { perror("fopen"); return -1; } // 使用文件 process_file(fp); // 关闭文件 fclose(fp);3. 可移植性使用 POSIX 标准接口避免使用平台特定扩展使用条件编译处理平台差异#ifdef __linux__ // Linux 特定代码 #elif defined(__APPLE__) // macOS 特定代码 #endif八、进阶主题1. 多线程编程虽然本书主要关注进程，但现代 Linux 编程中线程也很重要：pthread_create() pthread_join() pthread_mutex_lock() pthread_mutex_unlock()2. 异步 I/O// POSIX AIO aio_read() aio_write() aio_error() aio_return()3. 高级网络编程非阻塞 I/OI/O 多路复用（select/poll/epoll）零拷贝技术九、学习建议1. 学习路径graph LR A[C 语言基础] --> B[第1-3章 入门基础] B --> C[第4-5章 文件操作] C --> D[第6-8章 通用工具] D --> E[第9-10章 进程信号] E --> F[第12-13章 资源限制] F --> G[第14-17章 高级主题]2. 实践建议动手编译运行每个示例程序修改代码，观察不同行为使用调试工具跟踪程序执行尝试实现类似功能的程序3. 扩展阅读《Advanced Programming in the UNIX Environment》《The Linux Programming Interface》Linux 手册页：man pagesPOSIX 标准文档参考资料LinuxByExample-2e GitHub 仓库Linux 手册页POSIX 标准规范
SamWaf开源轻量级网站防火墙介绍一、新闻概述1. 标题SamWaf：面向小企业和个人站点的开源轻量级网站防火墙2. 发布时间2025年12月25日（最近更新）3. 来源GitHub 开源仓库二、核心内容1. 事件摘要A. 主要内容SamWaf 是一款开源轻量级的网站应用防火墙（WAF），专为小公司、工作室和个人网站设计，支持完全私有化部署。B. 核心亮点完全开源代码，支持私有化部署独立防护引擎，不依赖 Nginx、Apache、IIS数据本地加密存储，隐私保护到位一键启动，支持 Linux 和 Windows 64位、Arm64 平台支持 IPv6 和自动 SSL 证书申请续签2. 关键信息A. 版本状态GitHub Stars：1344+Fork：154+支持平台：Linux、Windows 64位、Arm64B. 代码仓库GitHub：https://github.com/samwafgo/SamWafGitee：https://gitee.com/samwaf/SamWafAtomGit：https://atomgit.com/SamSafe/SamWafC. 主要特性OWASP CRS 规则集支持CC 防护和 IP 黑白名单自定义防护规则日志加密存储管理端通信加密三、详细报道1. 主要功能A. 防护能力支持 OWASP CRS 规则集SQL 注入、XSS、RCE、扫描等攻击检测CC 攻击频率限制Bot 检测自定义规则脚本支持B. 访问控制IP 黑白名单URL 黑白名单白名单访问模式分网站单独防护策略C. 安全特性日志加密保存通讯日志加密信息脱敏保存数据本地化存储D. SSL 证书管理自动 SSL 证书申请（支持 Let's Encrypt 和 ZeroSSL）自动续签证书到期批量检测支持多云账号配置2. 架构设计graph TB Client[客户端] --> SamWaf[SamWaf 引擎] SamWaf --> WafEngine[WAF 防护引擎] WafEngine --> RuleEngine[规则匹配引擎] RuleEngine --> OWASP[OWASP CRS] RuleEngine --> Custom[自定义规则] SamWaf --> LogSystem[日志系统] LogSystem --> Encrypt[加密存储] WafEngine -.允许请求.-> Backend[后端服务] WafEngine -.拦截请求.-> Block[拦截页面] LogSystem --> Notify[告警通知] Notify -.邮件/企业微信.-> Admin[管理员]A. 工作原理SamWaf 采用反向代理架构，部署在客户端和后端服务之间：请求接收：SamWaf 监听 80/443 端口接收 HTTP/HTTPS 请求规则匹配：通过内置规则引擎对请求进行安全检测处理决策：根据匹配结果决定放行或拦截日志记录：所有请求经加密后存储到本地告警通知：触发告警条件时发送通知B. 核心组件WAF 防护引擎：核心防护逻辑规则引擎：OWASP CRS + 自定义规则日志系统：加密存储和查询SSL 模块：自动证书申请和管理通知模块：邮件、企业微信告警3. 技术细节A. 技术栈开发语言：Go 语言Web 框架：自研引擎前端：Vue.js数据存储：本地加密文件B. 部署方式Windows 系统# 直接启动 SamWaf64.exe # 服务模式安装 SamWaf64.exe install SamWaf64.exe startLinux 系统# 一键安装脚本 curl -sSO http://update.samwaf.com/latest/install_samwaf.sh && bash install_samwaf.sh install # 一键卸载脚本 curl -sSO http://update.samwaf.com/latest/install_samwaf.sh && bash install_samwaf.sh uninstallDocker 部署docker run -d --name=samwaf-instance \ -p 26666:26666 \ -p 80:80 \ -p 443:443 \ -v /path/to/your/conf:/app/conf \ -v /path/to/your/data:/app/data \ -v /path/to/your/logs:/app/logs \ -v /path/to/your/ssl:/app/ssl \ samwaf/samwafC. 访问配置管理界面：http://127.0.0.1:26666默认账号：admin默认密码：admin8684. 防护规则A. OWASP CRS 支持SamWaf 集成了 OWASP ModSecurity 核心规则集，提供以下防护：SQL 注入检测跨站脚本攻击（XSS）检测远程代码执行（RCE）检测扫描器检测文件包含攻击检测B. 自定义规则支持通过界面和脚本方式添加自定义规则：正则表达式匹配条件组合逻辑动作配置（拦截、放行、告警）四、影响分析1. 行业影响A. 市场定位填补了小企业和个人站长在网站安全防护领域的空白，传统 WAF 产品如 Cloudflare、阿里云 WAF 等主要面向中大型企业，费用较高。B. 竞争格局与 Nginx+WAF 模块、ModSecurity 等开源方案相比：部署更简单，一键启动独立引擎，不依赖 Web 服务器自带管理界面，开箱即用C. 技术趋势隐私保护需求上升，本地化部署成为趋势开源安全工具日益成熟边缘安全与本地安全相结合2. 用户影响A. 目标用户小型工作室和创业公司个人站长和开发者需要私有化部署的中型企业B. 使用价值降低安全防护成本简化 WAF 部署流程提供网站攻击可视化管理C. 迁移成本支持一键安装和升级配置迁移简单学习曲线平缓五、各方反应1. 社区反馈A. GitHub 数据1344+ Stars154+ Forks活跃的开发维护B. 功能评价优点：部署简单、界面友好、功能全面关注点：性能测试、大规模场景验证2. 生态支持A. 多平台支持Linux 各发行版Windows 7/10/11、Server 2008+macOS Intel/ArmDocker 容器化部署B. 文档支持在线文档：https://doc.samwaf.com/开发文档：https://doc.samwaf.com/dev/社区支持：GitHub Issues、Gitee Issues六、相关链接1. 官方资源GitHub 仓库：https://github.com/samwafgo/SamWaf在线文档：https://doc.samwaf.com/Docker Hub：https://hub.docker.com/r/samwaf/samwaf2. 下载地址GitHub Releases：https://github.com/samwafgo/SamWaf/releasesGitee Releases：https://gitee.com/samwaf/SamWaf/releases3. 反馈渠道GitHub Issues：https://github.com/samwafgo/SamWaf/issues邮件反馈：samwafgo@gmail.com参考资料SamWaf GitHub RepositorySamWaf 在线文档OWASP Core Rule Set
eBPF/XDP 构建二层直接服务器返回负载均衡器教程
eBPF/XDP 构建二层直接服务器返回负载均衡器教程一、概述1. 简介A. 是什么本教程讲解如何使用 eBPF/XDP 技术从零开始构建一个二层 Direct Server Return（DSR）负载均衡器。DSR 是一种高级负载均衡模式，允许后端服务器直接响应客户端请求，无需通过负载均衡器回传响应流量。B. 为什么学解决 NAT 模式负载均衡器的性能瓶颈问题掌握 eBPF/XDP 在网络编程中的实际应用理解 DSR 架构在云原生环境中的价值C. 学完能做什么使用 eBPF/XDP 实现二层 DSR 负载均衡理解虚拟 IP（VIP）的工作原理和配置方法掌握 MAC 地址重写技术在数据平面加速中的应用2. 前置知识A. 必备技能Linux 网络基础（IP、MAC、ARP 协议）基本的 C/Go 编程能力了解 eBPF/XDP 基本概念B. 推荐知识完成前序教程：NAT 模式 XDP 负载均衡器了解网络协议栈的分层模型二、背景知识1. NAT 模式的局限性在之前的教程中，我们构建了基于 NAT 的 XDP 负载均衡器。虽然该方案可以正常工作，但存在以下问题：A. 资源消耗负载均衡器需要处理双向流量（请求和响应），这会导致：更高的 CPU 和内存占用可能成为系统瓶颈B. 流量不对称入站流量通常远小于出站流量：搜索查询或 AI 提示只有几字节搜索结果或 AI 响应可能有数千字节C. 客户端信息丢失由于 NAT 负载均衡器重写了数据包头，后端服务器：无法感知真实客户端 IP难以维护用户会话无法按源 IP 记录请求日志2. Direct Server Return 概念DSR 通过让后端服务器直接响应客户端来解决上述问题。有多种 DSR 实现方式：Layer 2 DSR（本教程重点）IP-in-IP 封装GRE 隧道基于 IP 或 TCP 头部字段的变体三、实验环境1. 网络拓扑实验环境包含 5 个节点，分布在两个网络中：节点网络IP 地址lb192.168.178.0/24192.168.178.10/24backend-01192.168.178.0/24192.168.178.11/24backend-02192.168.178.0/24192.168.178.12/24client10.0.0.0/1610.0.0.20/16gateway跨网络192.168.178.2/24 + 10.0.0.2/162. DSR 原理与传统 NAT 负载均衡不同，DSR 保留原始客户端 IP，并允许后端直接响应客户端，在回程路径上绕过负载均衡器。核心问题：后端如何看到客户端 IP（数据包经过了负载均衡器）？后端知道响应哪个客户端吗？如何确保客户端从同一 IP 收到响应？简而言之，二层 DSR 通过在负载均衡器上仅重写数据包的 MAC 地址（保持 IP 头不变），并依靠负载均衡器和后端服务器之间的虚拟 IP 来实现。四、核心概念1. 虚拟 IP（VIP）在任何网络设置中，当客户端向特定端点发送请求时，期望响应来自相同的 IP 地址。如果响应来自不同的 IP，客户端网络栈会认为出错并丢弃数据包。在 NAT 负载均衡中，这会造成问题，因为客户端请求总是通过负载均衡器，后者将其转发给具有不同 IP 的后端节点。A. VIP 解决方案为了解决这个问题，负载均衡器和后端节点需要共享相同的 IP，确保客户端始终认为响应来自其最初联系的地址。这个共享 IP 就是虚拟 IP（VIP）。B. VIP 特性与物理 IP 不同，VIP 不绑定到特定接口或节点。相反，它是由多个节点使用的共享地址，用于处理同一服务的流量。2. VIP 配置A. 负载均衡器配置在负载均衡器的主接口（eth0）上配置 VIP：sudo ip addr add 192.168.178.15/32 dev eth0B. 后端服务器配置在两个后端服务器上，在环回接口（lo）上配置 VIP：sudo ip addr add 192.168.178.15/32 dev loC. ARP 隔离两个节点具有相同 IP 会引起混乱。因此，我们将 VIP 分配给后端节点的 lo 接口。我们不希望后端通过 ARP 广告虚拟 IP。网络中没有人应该知道后端上存在 VIP，否则客户端可能绕过负载均衡器直接连接。为防止后端节点响应 lo 接口上 VIP 地址的 ARP 请求（即广告），在每个后端节点上运行以下命令：# 仅当目标 IP 分配给接收请求的接口时才响应 ARP 请求 # （防止在 eth0 上广告 VIP） sudo sysctl -w net.ipv4.conf.eth0.arp_ignore=1 # 发送 ARP 请求时，仅使用分配给出站接口的地址 # （防止节点在 ARP 中泄露 VIP 作为源 IP） sudo sysctl -w net.ipv4.conf.eth0.arp_announce=2D. 工作原理负载均衡器实际上不需要知道后端节点上存在 VIP。它只需要后端的 MAC 地址在二层转发数据包。当后端接收数据包时，它会解封装数据包并将虚拟 IP 识别为自己的 IP（在 lo 接口上配置），即使该 IP 永远不会在网络上广告。这也解释了为什么这个概念称为二层 DSR——负载均衡器仅使用后端的 MAC 地址到达后端节点，如果后端位于不同的（二层）网络，这将无法工作。3. DSR 流程sequenceDiagram participant C as 客户端 participant G as 网关 participant LB as 负载均衡器 participant B as 后端服务器 C->>G: 请求到 VIP G->>LB: 路由到负载均衡器 LB->>LB: 选择后端（哈希） LB->>B: 重写 MAC 地址（保持 IP） Note over B: VIP 配置在 lo 接口 B->>G: 直接响应客户端 G->>C: 转发响应当客户端连接到 VIP 时：网关将流量路由到负载均衡器负载均衡器通过重写（源和）目标 MAC 地址将数据包转发到后端后端在 lo 接口上配置了 VIP，它将数据包识别为自己的并处理4. 前置准备在下一步之前，需要在负载均衡器上启用 IP 转发并填充 ARP 表，以便 bpf_fib_lookup 可以解析数据包目标：# 启用 IP 转发 sudo sysctl -w net.ipv4.ip_forward=1 # 填充 ARP 表 sudo ping -c1 192.168.178.11 # backend-01 sudo ping -c1 192.168.178.12 # backend-02五、实现细节1. MAC 地址重写现在我们理解了如何避免客户端困惑（总是收到来自相同 IP 的响应）。但还有一个问题：负载均衡器如何知道将流量发送到哪个后端——特别是当它们共享（相同）VIP 时？在二层 DSR 负载均衡中，我们实际上只需要在负载均衡器中更新 MAC 地址，以便数据包在二层正确传递。A. 后端选择使用简单哈希选择后端：// 选择后端 struct four_tuple_t four_tuple; four_tuple.src_ip = ip->saddr; four_tuple.dst_ip = ip->daddr; four_tuple.src_port = tcp->source; four_tuple.dst_port = tcp->dest; four_tuple.protocol = IPPROTO_TCP; __u32 key = xdp_hash_tuple(&four_tuple) % NUM_BACKENDS; struct endpoint *backend = bpf_map_lookup_elem(&backends, &key); if (!backend) { return XDP_ABORTED; }B. FIB 查询执行 FIB 查询获取转发信息：// 执行 FIB 查询 struct bpf_fib_lookup fib = {}; int rc = fib_lookup_v4_full(ctx, &fib, ip->daddr, backend->ip, bpf_ntohs(ip->tot_len)); if (rc != BPF_FIB_LKUP_RET_SUCCESS) { log_fib_error(rc); return XDP_ABORTED; }C. MAC 地址重写仅更新 MAC 地址：// 我们只需要更新 MAC 地址 // 后端需要在 lo 上有虚拟 IP（与负载均衡器相同） // 源 IP 保留为客户端，因此后端将直接响应它 __builtin_memcpy(eth->h_source, fib.smac, ETH_ALEN); __builtin_memcpy(eth->h_dest, fib.dmac, ETH_ALEN);D. 关键点这里很酷的事情是无需在负载均衡器中维护任何连接跟踪状态（与 NAT 负载均衡器不同）。我们只需基于通过 bpf_fib_lookup 在 fib_lookup_v4_full 中检索的 MAC 地址将数据包重定向到选定的后端节点，后端根据 IP 头直接响应客户端。负载均衡器甚至不触碰 IP 头，这意味着后端仍然接收原始客户端源 IP 并可以直接回复它，绕过负载均衡器。2. 源 MAC 地址说明源 MAC 地址也需要更新，以确保后端将响应正确发送回网关（而不是直接发送给负载均衡器）。六、运行负载均衡器1. 启动后端服务在两个后端服务器上启动 HTTP 服务器，显式绑定到 VIP 上监听请求：python3 -m http.server 8000 --bind 192.168.178.152. 编译并运行负载均衡器在 lab 目录下的 lb 标签页中：go generate go build sudo ./lb -i eth0 --backends 192.168.178.11,192.168.178.12参数说明：-i eth0：指定网络接口--backends：后端服务器 IP 列表（逗号分隔）3. 测试负载均衡从客户端标签页查询 VIP：curl http://192.168.178.15:8000确认请求确实是从客户端接收的（IP 在行首）：10.0.0.20 - - [01/Jan/2026 16:03:45] "GET / HTTP/1.1" 200 -4. 验证数据流向A. 使用 tcpdump在两个后端上运行 tcpdump 查看 MAC 地址：sudo tcpdump -i eth0 -n -t -e -q tcp port 8000预期输出（简化）：LB_MAC > BACKEND_MAC, IPv4, length 74: CLIENT_IP/PORT > BACKEND_IP/PORT: tcp 0 # 负载均衡器 -> 后端（同时保留客户端源 IP） BACKEND_MAC > GATEWAY_MAC, IPv4, length 74: BACKEND_IP/PORT > CLIENT_IP/PORT: tcp 0 # 后端 -> 网关（其中客户端 IP 是目标）B. 使用 bpftool检查负载均衡器日志：sudo bpftool prog trace七、架构图graph TB subgraph 客户端网络 C[客户端 10.0.0.20] GW[网关 10.0.0.2/192.168.178.2] end subgraph 服务器网络 VIP[虚拟 IP 192.168.178.15] LB[负载均衡器 192.168.178.10] BE1[后端-01 192.168.178.11 VIP on lo] BE2[后端-02 192.168.178.12 VIP on lo] end C -->|请求到 VIP| GW GW -->|路由| LB LB -->|重写 MAC| BE1 LB -->|重写 MAC| BE2 BE1 -->|直接响应| GW BE2 -->|直接响应| GW GW --> C style VIP fill:#f9f,stroke:#333,stroke-width:2px八、局限性二层 DSR 仅在负载均衡器和后端位于同一子网（即具有直接二层连接）时才能真正工作。如果负载均衡器尝试将流量重定向到不同二层网络中的后端：它会将目标 MAC 地址设置为网关接口（尝试退出当前二层网络）由于只有负载均衡器上的 VIP 在整个网络上广告，网关会将数据包发回负载均衡器因为这是网关知道的该 VIP 的唯一路由这会导致环路A. 约束要求后端与负载均衡器共享同一网络负载均衡器和后端节点托管在同一子网会增加完全故障的风险B. 解决方案这是 IPIP DSR 负载均衡发挥作用的地方——将在后续教程中介绍。九、总结1. 核心要点DSR 允许后端直接响应客户端，绕过负载均衡器二层 DSR 通过重写 MAC 地址实现，保持 IP 头不变VIP 配置在负载均衡器的实接口和后端的 lo 接口上需要 ARP 隔离防止后端广告 VIP2. 优势负载均衡器资源消耗降低后端可以看到真实客户端 IP更适合出站流量大的场景3. 局限要求负载均衡器和后端在同一二层网络跨网络部署需要 IPIP 或 GRE 等隧道技术参考资料Building an eBPF/XDP L2 Direct Server Return Load Balancer from Scratch
Guix System First Impressions as a Nix User
Guix System First Impressions as a Nix UserTable of ContentsMy Journey to Guix SystemInstaller ImpressionsI Can't Find my Way-landSympathy for the DevilGoalsResultsOverallNotes1. My Journey to Guix SystemI've been a Linux-only user for about ten years now and, like many others, I too embarked on the arduous journey of distro-hopping. I started with Mint and when that felt too slow, I switched to Ubuntu. When Ubuntu felt too handholdy, I switched to Arch, which proved to be my main driver for well over five or so years. And when I couldn't resist the Siren's call, I moved on to Gentoo, thinking surely "harder is better". Which resulted in severe burnout in a few months, so I capitulated and switched to Fedora, which was very stable and honestly an all around excellent system. But once more, my interest was piqued, and (before today's adventure) I finally switched to NixOS.I've always had a passing interest towards Nix ever since I've first heard about it, but until fairly recently, I always dismissed it as a tool for DevOps guys. The syntax was weird, the need for reproducible environments seemingly irrelevant, and stuff like the oft-recommended Nix Pills seemed anything but newbie-friendly.So then why would someone like me, who's so adamant about not needing Nix eventually choose to go all-in? I guess it was at first less about Nix being better and just the rest being worse.Of the two big reasons for the switch, one was that I realized that having per-directory environments for your projects is actually a very handy thing to do when you like to toy around with many technologies. I used to generate my other blog using Jekyll and, no matter which distro I used, it was always a pain in the neck to have a good Ruby environment set up. bundler install didn't really want to work without privileges and I wasn't really a fan of unleashing sudo on it, but usually that was the only way I could get things to work.With Nix, however, it was a matter of just describing a few packages in a shell and boom, Ruby in one folder, no Ruby (and thus no mess) everywhere else. I was hooked! I started adding shell.nix files to all my little projects, hell, I started planning projects by first adding a shell.nix with all the dependencies I would reasonably need.The other reason, which ultimately cemented that I need to commit, was that I was getting tired of my installed packages slowly drifting out of control. Sure, every package manager has some method of listing what's installed, but these are usually cumbersome and completely ephemeral (in the sense that any listing becomes invalid the moment you change anything).With NixOS, the equation is flipped on its head: No longer did I query the system to tell me what's installed and what's not, it was now the system that worked based on files that I edit. The difference sounds small on paper, but for me it was an extremely liberating feeling to know that I could edit my system configuration in a versionable, explicit, and centralized way.But NixOS isn't the only declarative distro out there. In fact GNU forked Nix fairly early and made their own spin called Guix, whose big innovation is that, instead of using the unwieldy Nix-language, it uses Scheme. Specifically Guile Scheme, GNU's sanctioned configuration language. I've been following Guix for a bit, but it never felt quite ready to me with stuff like KDE being only barely supported and a lot of hardware not working out of the box.However, now that (after three years) Guix announced its 1.5.0 release with a lot of stuff stabilized and KDE finally a first-party citizen, I figured now is the best time to give it a fresh shot. This post captures my experiences from installation to the first 3-4 days.2. Installer ImpressionsPlug your USB in, dd the file onto the drive, reboot, nothing unusual. If you've ever installed a Linux system, it's more of the same.After selecting the pendrive in my BIOS settings, the monitor began to glow in a deep, radiant blue as the Guix System logo appeared on my screen… only to suddenly switch to a menacing red: My CPU's integrated GPU is not supported by free firmware. A helpful popup gave me a gentle nudge about picking free hardware next time (buddy, have you seen the PC part prices these days?) and off I went into the installer proper.The installer itself is refreshingly barebones and I mean this in a positive way. It asks all the necessary questions and provides a nice basic configuration file, all done in a retro Ncurses-based TUI. I was really happy to see that, unlike my last attempt at using Guix System in the early 2020-s, KDE Plasma is now a first-party choice during installation. I never really vibed too much with GNOME and the other options didn't appeal either, so the choice was obvious.Now, I'm not sure if I just picked the worst possible time or if the Guix servers were facing unusual load or whatever may have happened, but after such a breeze of a setup, the moment I pressed install, my PC became unusable for the next 2.5 hours. Which is unacceptable for an installation process these days in my opinion. I am lucky enough to live in a household with fiber-optic internet, that merely shrugs at bandwidth of up to a gigabyte per second and yet nearly all packages downloaded with a whopping 50 kilobytes per second, meaning even small-ish 5-10 megabyte packages took long minutes to download.A reboot later my issues only got worse.3. I Can't Find my Way-landI was assuming I'd get SDDM after having chosen KDE Plasma, but (what a later, closer read of the manual made me realize is the expected outcome for a default config) it was GDM that loaded in. I entered my name and password, and I was greeted with the familiar Plasma 6 spinner. The first hint that something might be off was that it loaded a bit longer than usual, but I was not going to get mad at waiting 10 seconds instead of 3. After all, I did just wait magnitudes longer to get here.With practically nothing installed beyond the very basics, I clicked on Konsole, hoping to start prodding around my config and add some of my day to day apps. To my horror, it opened in the top left corner, without a titlebar and without any borders. What's more, no matter what I did, I couldn't move it. It also didn't show up on the menu bar, despite the application launcher still being completely usable. At this point I was fairly exhausted by these antics, but I figured,Well, it's a brand new release, perhaps this just snuck in. Let's give updating a shot and see if that helps.So I issued guix pull… The download whizzed by with speed quite unexpected after what I experienced with the installer… Only to crash into the brick wall that's indexing. Okay, whatever, another 10-12 minutes down the drain, at least now I have newest version.Except I didn't. Because, unlike Nix, the guix executable is not an omnipresent, unique thing that anyone and everyone uses on your PC. Not only does every user have their own instance, if you don't issue a certain set of commands, you won't start using the new version, despite updating it.To Guix's credit, the CLI does scream at you to update your environment or else you'll keep using the old version, but I still find this system very disorientating compared to Nix. I'm certain experienced Guixheads are long past being tripped up by this sort of stuff and might even struggle to remember that there was a time they had to do these special steps too, but as a new user it felt a bit rough, especially consdering this is Guix System, i.e. the system whose whole purpose is to be integrate Guix as much as it can.Back to our issue at hand. I issued sudo -s and guix pull-ed again. Once more 10-12 minutes passed indexing. But at least I could finally call guix system reconfigure /etc/config.scm. Interestingly things are much faster this time around, I saw speeds up to 30-50 Mbps. Before long the system was updated to the newest commit and I rebooted with high hopes.High hopes, that were immediately dashed when Plasma loaded in the same messed up way. At this point I started to suspect this might be an issue with the GPU driver, so I enabled the LXQT desktop environment and rebooted once more. Thankfully that one worked like a charm and I was able to boot up both Emacs (editing Scheme with GNU Nano is a pain I do not wish on anyone) and LibreWolf (Firefox's de-Mozilla-d variant).Not having found anything too useful in the docs, I decided to make my problem someone else's so I fired up ERC and connected to Libera.chat's #guix channel. After around half an hour of wait, a user by the name of Rutherther stepped up and offered me some help. We were able to figure it out that Nouveau wasn't able to drive my GPU (an RTX 5070), so his recommendation was that I should try booting with nomodeset. I did, but it sadly didn't help much either.4. Sympathy for the DevilAt this point I was out of ideas. Ideas of solving this using pure-Guix System, that is. There was still one option I wanted to avoid as long as I could, but alas, it seemed like the only option, that still had a realistic chance of working.Enter Nonguix, the Mr. Hyde to Guix's Dr. Jekyll, the shady guy who offers you a hit and first time's for free, the… Erm, in a nutshell, it's the repository for non-free applications and drivers packages for Guix System, basically. Interestingly enough, by Guix's own findings about 64% of users utilize the Nonguix channel, which is perhaps not "literally everyone", but it does paint a picture that there is still stuff out there that you simply cannot replace with FOSS software yet.Listing 1: At the time of writing, this is all one has to do to enable Nonguix.(cons* (channel (name 'nonguix) (url "https://gitlab.com/nonguix/nonguix") (introduction (make-channel-introduction "897c1a470da759236cc11798f4e0a5f7d4d59fbc" (openpgp-fingerprint "2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5")))) %default-channels)Enabling the repo wasn't exactly difficult. You just paste the short excerpt from above (also found in the README) into your ~/.config/guix/channels.scm and /etc/guix/channels.scm files, guix pull, let it index to its heart's content again, and then you have access to all that is nasty (yet occasionally useful) in the world.I figured perhaps if Linux-libre and its free firmware couldn't deal with my GPU, then surely Linux proper with its binary blobs could. Hell, for good measure I threw in the NVIDIA transform, which is supposed to automagically translate all dependencies to use the proprietary drivers.Turns out my eagerness was a mistake. Not only did the process take yet another half an hour (if not more, I stopped counting), upon reboot all I was met with was a kernel panic about the driver not being able to cope with the GPU it found and a massive spew of FSCK logs.With no better ideas in mind, I took out my pendrive again and burned Nonguix's own pre-built ISO on it using my partner's PC. While it ultimately did get me a working system, this version has three unfortunate hindrances:It was built in 2022, far before Guix's migration to Codeberg, meaning it still attempts to pull content from the unfathomably slow GNU Savannah mirror. I had to manually override my channels.scm to point at the Codeberg repo instead, but with no easy means of finding its "channel introduction", I had to pass in --disable-authentication to Guix when updating my system. A bit scary, but I trust the Codeberg repo.Because of its age, I got a lot of somewhat intimidating errors about hardware not being recognized and other stuff I couldn't even decipher, but ultimately the system booted to the installer without issue.For some reason while the installer itself does include Nonguix stuff, it actually does not include the repo in the resulting channels files, nor the substitution server for the project. The README has a warning about this, but if you happen to miss it, you could accidentally install a non-Nonguix Guix System (say that three times fast).None of these were particularly hard to fix, however, and soon enough I was back where I started. That is to say, in a nomodeset X11 session, except this time running i3, as LXQT wasn't an available option on an installer this old. There was certainly a bit of a hacker-ish vibe to messing with code files in an environment like that, but I was honestly much more looking forward to finally having a usable desktop.Having learned from my hastiness, this time I was smarter. I only enabled the full kernel and firmware blobs, without going anywhere near the NVIDIA transform. I issued another guix system reconfigure and, after having time for another tea session, my update was finally finished.I rebooted with tentative nervousness and… Success? Huh.5. GoalsObviously there is little point in throwing Guix System on my PC and declaring success. I wanted to be able to at least reproduce the kind of workflow I'm used to using NixOS. For that, I need the following:A browser: preferably Firefox, as I'm not a huge fan of Chrome / ChromiumAn E-mail client: preferably ThunderbirdA basic office suite: preferably LibreOfficeDev environments: for Rust, Zig, Scheme, and TypeScript (with the option for more, if possible)Emacs: I do almost all my text editing in it these days, falling back to Neovim for quick tasksDiscord: for chatting with friendsTelegram: for chatting with familySteam: for the very rare occasions I want to gameNVIDIA drivers: I prefer to offload day-to-day usage to my CPU's integrated GPU, as it cuts my energy usage in half.Of these it was obvious that two would be relatively hard and one "outright impossible". The two being Steam and the drivers (as both are non-free and thus not in Guix's default repos) and the "impossible" one being Discord (which not even the non-free repo has packaged). But I was ready to compromise a little bit since I am requesting stuff that's explicitly against Guix's goals.6. ResultsWhile there has been occasional bumps and hitches along the ride, I must say I'm very impressed with Guix System so far. Let's go through this list in order:Browser: So far I'm really enjoying LibreWolf. It feels a lot snappier than Firefox and I'm really baffled how much speed I was apparently missing out on.E-mails: I installed Icedove, which is basically just Thunderbird without Mozilla branding. It works as expected.Office suite: LibreOffice is available as expected. Not much to say about it. I guess it's interesting that Guix isn't following the usual -stale / -fresh packaging schema, but I don't really mind not having cutting edge versions of an office suite :)Dev environments: I've only briefly toyed with development environments so far, but to me it seems like for simple use-cases it might be even easier to use than shell.nix (you don't need any sort of ceremony, just a manifest.scm file with a (specifications->manifest ) form inside and you have a dev env ready to go.)Emacs: Installed just fine. I had to install emacs-vterm to make Vterm work, but all that took was the very simple process of adding the library to my home configuration and then referencing it in my Emacs config as per this Reddit post.Discord: I decided to just use Discord's browser version, which works just as fine (if not better). It's trading a tiny bit of convenience in return for not having to figure out how to manually add a package for it from some random third-party source. From what I've read elsewhere Flatpak is also an option, but I prefer having just one package manager at a time.Steam: Installed shockingly easily. I have to really give props to the Nonguix team. I tested Portal 2 with the Nouveau driver, it is a little disheartening to see a 15 years old game lag, but I understand the people's hands are tied when it comes to the free drivers. After I managed to install the proprietary drivers, I was able to play even Portal RTX, which is something I never managed to get to work using NixOS.NVIDIA drivers: This time I actually read the docs properly and it didn't take long for me to realize the initial problem that caused my previous install to be unbootable was of course found between the chair and keyboard. This time, after making sure I enabled the open drivers and kernel mode-setting, I crossed my fingers, issued a reconfigure and it works beautifully!6.1. The GoodHelpful community: While I do feel like Guix's community could be much larger (see below), the one that exists is very helpful and nice from my limited experience. In all places I've looked so far (Libera's #guix, /r/Guix, and the guix/guix Codeberg repository) I was met with genuinely kind and helpful people.Home configuration: Having guix home be a built-in, first class citizen, instead of a community made "extension" is excellent. Instead of needing to consult a third-party resource like Home Manager's documentation you can simply use what you already know about Guix and, if you happen to hit a wall, you can just read the official handbook which is guaranteed to always stay up to date with the rest of the system.Package availability: As long as you largely use FOSS stuff (which is much easier than one might think), the amount of choice is awesome. I could basically just copy over the list of packages from my Nix config and practically everything had an equivalent.Scheme: I'm not really a seasoned Schemer, but I have dabbled in the language previously and it feels so much better to me than Nix (the language) ever did. One great benefit of this is that it's a lot easier to start digging into package definitions to figure things out for yourself.This is "Freedom 1" of GNU's Four Essential Freedoms in effect. Since the code is pretty much just Scheme and the different mechanisms available are fairly well documented, the barrier to entry is much lower than with Nix in my opinion.Another nice benefit of this is that you can use Emacs' extensive Scheme support to help your configuration. Tools like Geiser can plug right into Guix and help you find package and function names and, once you're experienced enough, debug your config/packages on the fly.Ease of hacking: In the "to tinker on" sense, rather than "being insecure". With Nix, merely pulling in Nixpkgs is an effort, due to the repository being massive. My otherwise beefy machine struggled to switch between branches and make commits, which doesn't exactly inspire confidence in contributing, even though it was otherwise something I was excited to do. Meanwhile, with Guix I was able to get a fully functioning development environment in 15 minutes tops, which includes cloning the repo, authenticating all commits, generating bytecode for the entire repository, and getting Emacs set up to work nice with the codebase.6.2. The AmbiguousSearch: guix search not taking an extra parameter like nix search is both very convenient and a bit of a bummer.Its absence is not a deal breaker, but I really loved how with Nix, you could search in anything, that has a flake. Be that Nixpkgs, a repo you downloaded, a repo that's on a git forge, etc. I remember being awestruck that I could just do nix search github:mozilla/nixpkgs-mozilla and search for their builds of Firefox without having to manually check out anything.The documentation: Oof, this one is a bit hard to pass definite judgment on.On one hand I love the thoroughness of it all. You can get a fairly decent idea of what Guix, what it can do for your, how to use it, and how to extend it, just by reading the manual. It is evident that the Guix team and GNU in general takes its mission to educate using free software very seriously. Stuff like the Packaging tutorial make it very easy for complete beginners to hack together package definitions without needing to consult any other resource.On the other hand, it really is just a manual, not a tutorial. What I mean by this is that concepts that could belong together aren't placed near each other. A simple example would be services and customizing them. Assuming, you're in one of the sub-pages of Services and you suddenly realize you want to replace/modify one of the services, you are left completely clueless how that works. You have to go to a completely different chapter and find one particular function's description and then apply what you learn there. The Guix Cookbook has some examples, but you have to know about the cookbook in the first place.6.3. The BadSubstitute server stability: I imagine this is an issue that only a massive bag of money could fix, but the CI/CD servers could definitely use some more processing power. It's really annoying when you're trying to test something and you're suddenly forced to wait 10-15 minutes because the server can only spare 50-100 kbps for you.Content out there: Clearly this isn't the Guix team's fault (and it's something I'm trying to lessen with this post, even if just a tiny bit), but it's really hard to find good quality material when it comes to Guix.I mean, sure, there is the excellent System Crafters tutorial series, and the odd gems like DThompson's dev env tutorial, but as a whole you're largely left to your own to trawl through the manual, IRC logs, Reddit threads, Codeberg and the previous issue tracker, etc.Guix's own build speed: Nix excels in speed, so I was hoping Guix would be the same. Yet stuff like guix pull really bog things down. Doubly so, if you want to update not just your own guix instance, but also root's.Clarity of commands: The fact that all concerns are lumped together (unlike Nix's many utilities) means that to the new user the many commands such as guix pull, guix {system, home} reconfigure, guix update can easily feel overwhelming and unclear what's updating/changing what.7. OverallIn a nutshell I'm very positively surprised by Guix System. After struggling so much with it years ago, this time everything just clicked after a much shorter battle. So much so that I'm happy to make it my daily driver for the foreseeable future. Beyond the slightly slower execution speed, I'm getting a comparable experience to NixOS, with all the usual pros a declarative environment brings and without having to put up with Nixlang.My only recurring issues so far are the occasional slow download speeds and that I have to start my kernel in nomodeset because otherwise the graphical environment crashes without me being able to switch to a TTY. It's a bummer, but honestly, I'm not too bothered by it so far. I'm trusting a driver update will fix it soon enough and, if not, it's not exactly difficult to throw in a kernel parameter into your config.I'm hoping to do a followup post about packaging in Guix, because I've been dipping my toes into it by trying to package Wezterm and the journey there was similarly arduous as installing the system itself.8. NotesThe installer is decently simpleI appreciate the warning about incompatible hardware2.5 hours at least to install (mirrors throttle connection to 50kbps)KDE is simply not working out of the box (titlebars are missing)It seems to also default to X11, when I'm looking for WaylandThe first guix pull is horrendously slowWayland continues to elude me, seems to be an Nvidia issueIRC recommends nomodeset, doesn't helpTry enabling Nonguix, system no longer bootsTry installing using the Nonguix ISOLots of errors, terribly old releaseHaving to guix pull myself to the present day againAlso I'm missing the introduction, so I have to run it using --disable-authentication, not great, but I trust the Codeberg repoAt least the download speed seems to have normalizedIt isn't entirely clear when you have to use sudoRunning i3 on a shitty low-res has a certain vibe to it, but I'd prefer a system working out of the boxReferencesOriginal article: https://nemin.hu/guix.htmlGNU Guix: https://www.gnu.org/software/guix/Nonguix Repository: https://gitlab.com/nonguix/nonguix
Linux环境变量问题技术分析一、概述1. 问题背景在日常Linux运维和开发工作中，环境变量相关的问题是导致脚本执行失败的主要原因之一。这类问题通常表现为：命令在交互式终端中正常执行，但通过 crontab、SSH 远程执行或自动化工具执行时却报错找不到命令。2. 核心问题脚本在命令行测试正常，放入 crontab 后报错找不到命令SSH 远程执行命令时环境变量与本地登录不同Docker 容器中环境变量传递问题Bash 与 Sh 语法兼容性问题3. 影响范围自动化脚本执行失败定时任务无法正常运行容器化应用启动异常跨平台脚本兼容性问题二、问题分析1. Login Shell 与 Non-Login ShellA. 核心区别Linux Shell 分为两种模式：Login Shell（登录式 Shell）和 Non-Login Shell（非登录式 Shell），它们加载环境变量的顺序不同。B. 环境变量加载顺序graph TD subgraph Login Shell A1["/etc/profile"] --> A2["~/.bash_profile"] A2 --> A3["~/.bashrc"] A3 --> A4["/etc/bashrc"] end subgraph Non-Login Shell B1["~/.bashrc"] --> B2["/etc/bashrc"] end C["用户登录"] --> Login D["SSH远程执行命令"] --> Non-Login E["Crontab执行"] --> Non-Login F["脚本调用"] --> Non-LoginC. 关键差异Login Shell 加载顺序：① /etc/profile ② ~/.bash_profile ③ ~/.bashrc ④ /etc/bashrcNon-Login Shell 加载顺序：① ~/.bashrc ② /etc/bashrc/etc/profile 中包含 pathmunge 函数，负责将 /usr/sbin、/usr/local/sbin 等路径添加到 PATH 变量中。Non-Login Shell 由于跳过了 /etc/profile 的加载，导致这些路径缺失。2. 实际场景分析A. SSH 远程执行命令# 直接登录后执行（Login Shell） ssh user@ip ip a # 正常执行 # 远程直接执行命令（Non-Login Shell） ssh user@ip "ip a" # 报错：bash: ip: command not found原因分析：Login Shell：PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbinNon-Login Shell：PATH=/usr/local/bin:/usr/binip 命令位于 /usr/sbin 下，Non-Login Shell 的 PATH 中不包含该路径。B. Crontab 定时任务脚本在命令行测试正常，放入 crontab 后报错找不到命令。这是因为：命令行执行使用当前用户的完整环境变量Crontab 执行时的环境变量被 sudo 修改（如果使用 sudo）sudo 默认会重置环境变量3. Bash 与 Sh 的区别A. 命令差异命令/特性BashSh (POSIX)source内建命令不支持（用 . 代替）语法扩展支持数组等仅 POSIX 标准 B. 系统链接差异CentOS：/usr/bin/sh → /usr/bin/bash（sh 等同于 bash）Ubuntu：/usr/bin/sh → /usr/bin/dash（sh 是独立的 dash）这就是为什么在 CentOS 上用 sh 执行的脚本在 Ubuntu 上可能报语法错误。三、解决方案1. Crontab 环境变量问题A. 使用 sudo -E 参数# 在 crontab 中使用 sudo -E /path/to/script.sh-E 参数（--preserve-env）可以保留当前用户的环境变量。B. 脚本中显式加载环境变量#!/bin/bash # 在脚本开头添加 source /etc/profile source ~/.bashrcC. 脚本使用 login shell#!/bin/bash --login2. SSH 远程执行问题A. 创建全局环境变量文件在 /etc/profile.d/ 下创建自定义环境变量文件：# /etc/profile.d/my_bashenv.sh pathmunge () { if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then if [ "$2" = "after" ] ; then PATH=$PATH:$1 else PATH=$1:$PATH fi fi } pathmunge /sbin pathmunge /usr/sbin pathmunge /usr/local/sbin pathmunge /usr/local/bin/etc/bashrc 会自动加载 /etc/profile.d/ 下的所有 *.sh 文件。B. 使用 SSH -t 参数ssh -t user@ip "command"-t 参数强制分配伪终端（TTY），可以触发 login shell。3. Docker 环境变量问题A. 问题现象docker run 时传入的环境变量，root 用户可见通过 crond 以 admin 用户执行时无法读取B. 解决方案在 Docker 镜像构建时修改 /etc/bashrc 和 ~/.bashrc：将 . /etc/bashrc 改为 source /etc/bashrc确保 /etc/profile.d/dockerenv.sh 被正确加载4. 通用最佳实践A. 脚本开头统一使用#!/bin/bash --login set -euxo pipefail--login：确保使用 login shell-e：遇到错误立即退出-u：使用未定义变量时报错-o pipefail：管道中任何命令失败都返回失败状态-x：打印执行的命令（调试用）B. 使用绝对路径在脚本中尽量使用命令的绝对路径：/usr/bin/docker instead of docker /usr/sbin/ip instead of ipC. 显式设置 PATH#!/bin/bash export PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:$PATH四、深入原理1. 环境变量继承机制A. 进程创建与变量继承sequenceDiagram participant P as 父进程 participant E as 环境变量 participant S as 子进程 P->>E: export VAR=value E->>E: VAR 变为环境变量 P->>S: fork + exec E->>S: 继承环境变量 S->>S: 可访问 VAR Note over P,S: 未 export 的自定义变量不会被继承B. export 命令作用默认：子进程仅继承父进程的环境变量export：将自定义变量转换为环境变量，使子进程可继承2. Shell 执行方式差异A. 三种执行方式对比方式进程环境变量变量作用域source script.sh当前进程共享变量在当前 shell 生效bash script.sh子进程独立变量不带回父 shell./script.sh子进程独立变量不带回父 shellB. 验证实例# 测试脚本 test.sh echo $$ # 显示进程 ID # 执行结果 echo $$ # 2299（父进程） source test.sh # 2299（同一进程） bash test.sh # 4037（新进程） ./test.sh # 4040（新进程）3. Su 命令的差异A. su 与 su - 的区别su：只切换用户身份，Shell 环境保持不变su -：切换用户身份和 Shell 环境（包括工作目录和环境变量）B. 实际影响su admin # 重新加载 ~/.bashrc # 工作目录不变 su - admin # 不重新加载 ~/.bashrc # 切换到 admin 的 home 目录五、常见问题与排查1. 命令找不到A. 排查步骤# 1. 确认命令位置 which ip type -a ip # 2. 检查 PATH echo $PATH env | grep PATH # 3. 确认当前 shell 类型 echo $0 echo $-B. 判断标准$0 包含 -bash 表示 login shell$- 包含 i 表示交互式 shell不含 i 和 - 的是非交互式非登录 shell2. History 命令无输出A. 原因history 是 bash 内部命令，在非交互式环境中默认关闭。B. 解决方案# 在脚本中开启 set -o history3. Source 命令找不到A. 错误信息source: not foundB. 原因使用 sh 执行脚本，但 source 是 bash 内建命令。C. 解决方案使用 bash 执行脚本或将 source 改为 .（POSIX 兼容）六、Shell 调试技巧1. 启动参数参数作用-n只检查语法，不执行-v执行前输出每行语句-x执行后输出每个命令2. 使用示例bash -n script.sh # 语法检查 bash -v script.sh # 显示执行过程 bash -x script.sh # 调试模式七、参考资料参考资料Linux环境变量问题汇总 - planteggBash Startup Files - GNU ManualBash Reference Manual