
上周出差酒店房间只给了一个有线网口。笔记本插上去能上网可我手机和平板全都干瞪眼。当时我在 Debian 11 笔记本上敲了一组命令行把自带的无线网卡变成了一个 WiFi 热点整个过程不到十分钟。核心工具就是两个负责把无线网卡变成 AP 的 hostapd以及负责给客户端分配 IP、应答 DNS 的 dnsmasq。很多人第一次做这事都会卡在莫名其妙的地方热点明明起来了手机也连上了却就是上不了网或者网卡驱动根本不支持 AP 模式再或者重启后热点再也起不来。这篇文章我会把我实际跑通过的流程完整写出来包括配置文件逐行解释、NAT 转发、systemd 自启以及我踩过的一堆坑。适合两类读者一是想在 Debian/树莓派上临时开热点的用户二是想彻底搞懂 Linux 无线热点原理、以后遇到问题能自己定位的同学。1. 开始之前先确认“能不能做”网卡、驱动与网络拓扑1.1 不是所有无线网卡都能开 AP先查硬件开 WiFi 热点不是单纯敲几条命令的事硬件不支持就是白搭。Linux 下无线网卡要变成 AP需要驱动通过 nl80211 协议栈向内核注册 AP 能力。判断方法很简单终端执行iw list | grep -A 15 Supported interface modes输出里会列出该网卡支持的接口模式比如managed、monitor、AP、mesh point等。你需要确认其中出现了AP。如果只有managed那这张网卡基本上只能连接别人的 WiFi不能自己发射热点。这一步还有个很容易忽略的细节虚拟机里的无线网卡基本都不支持USB 无线网卡要特别看芯片方案某些廉价 RTL8188 方案的卡在 Debian 11 上驱动不全开了 AP 也不稳定。我个人的经验是优先选择 Intel 无线网卡或者 Atheros/MTK 方案的 USB 网卡踩坑概率低很多。提示如果iw list输出为空通常是 wireless-regdb 或驱动固件没装好。先执行iw phy看看有没有 phy 设备没有的话说明无线网卡压根没被驱动识别。1.2 只有一块无线网卡时想边上网边开热点必须看这个这是新手最容易掉进去的坑笔记本自带无线网卡连着公司 WiFi然后还想用同一张网卡开热点给手机用。能不能做到取决于网卡是否支持 STAAP 并发模式。检查方法iw list | grep -A 8 valid interface combinations如果输出里类似{ managed AP }这样的组合说明驱动允许一个物理网卡同时作为工作站和 AP。Intel 的 AX200、AX210 等卡通常支持。但即便支持NetworkManager 那边也容易打架我个人不推荐在关键场合依赖这种单卡并发。最稳的拓扑其实是两种有线网口做上行eth0 连到路由器或酒店网口无线网卡 wlan0 专门做 APUSB 无线网卡做 AP板载无线网卡连上级 WiFi。本文后面的配置默认是第一种eth0上网wlan0开热点。如果上行链路是wlan0连上级 WiFi而开热点的接口是wlan1原理完全一样只需要把配置里对应的接口名改掉。1.3 系统准备关掉 NetworkManager 的抢占解除 rfkill 封锁Debian 11 安装完 hostapd 和 dnsmasq 之前先记得更新软件源并安装工具apt update apt install -y hostapd dnsmasq iw装完后先别急着配置有个关键步骤把无线网卡从 NetworkManager 手里“抢”出来。如果 NetworkManager 还管理者 wlan0它会在你启动 hostapd 时试图把网卡切回 managed 模式连接已知 WiFi导致 hostapd 异常退出。nmcli device status nmcli device set wlan0 managed no ip link set wlan0 up还要用rfkill list检查无线设备是否被软封锁如果是执行rfkill unblock wifiDebian 安装 hostapd 后会自动创建一个 systemd 服务默认因为缺少配置文件而启动失败dnsmasq 的系统服务默认也会跑起来并占用 53/67 端口。为了不干扰后面的自定义方案建议先把这两个服务停掉并 masksystemctl stop dnsmasq.service systemctl disable dnsmasq.service systemctl mask hostapd.service2. 配置文件怎么写hostapd.conf 和 dnsmasq.conf 的分工2.1 hostapd.conf让无线网卡变成“路由器的那部分”hostapd 负责的是链路层也就是把无线网卡模拟成 AP处理客户端关联、加密、认证。我使用的配置文件在/etc/hostapd/hostapd.conf内容如下interfacewlan0 drivernl80211 ssidMyDebianHotspot hw_modeg channel6 wmm_enabled1 macaddr_acl0 auth_algs1 ignore_broadcast_ssid0 wpa2 wpa_passphraseYourStrongPassword wpa_key_mgmtWPA-PSK rsn_pairwiseCCMP country_codeCN ieee80211d1逐项拆开说interfacewlan0指定哪张网卡做 AP必须和实际接口名一致可以用ip -br link确认drivernl80211现代 Linux 网卡驱动都是这种不要改成别的ssid热点名建议只用纯 ASCII 字符最大 32 字节UTF-8 SSID 在部分老设备上显示乱码hw_modegg 表示 2.4GHza 表示 5GHz要看网卡支持哪个channel62.4GHz 推荐用 1、6、11 里的一个这三个信道互不重叠。不建议设 0 自动选频在某些驱动上会自动跳到 DFS 信道反而引发客户端掉线wpa2强制 WPA2兼容性最好wpa_passphrase密码必须 8 到 63 个字符rsn_pairwiseCCMP加密算法用 AES不要用 TKIPcountry_codeCN监管域国家码会影响可用信道和发射功率。不同国家允许的信道不同如果你不在中国改成当地 ISO 国家码。不设置的话部分网卡会锁在 2.4GHz 且功率降低ieee80211d1让热点广播国家信息元素客户端的漫游行为会更规范。如果你想开 5GHz 热点配置文件改成hw_modea channel149 ieee80211n1 ieee80211ac1 ht_capab[HT40][SHORT-GI-20][SHORT-GI-40] vht_capab[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][MAX-A-MPDU-LEN-EXP3]5GHz 下有个大坑信道 52-64 和 100-140 属于 DFS 信道要避让雷达。如果 hostapd 自动选频时选中这些信道客户端连接后可能每隔一会儿就断一次因为雷达检测触发跳信道。所以手动固定到 149、153、157、161 这类非 DFS 信道省心很多。2.2 dnsmasq.conf给客户端发 IP、应答 DNS 查询dnsmasq 负责三件事DHCP 分配 IP、DNS 转发、以及部分路由公告。为了不弄乱系统原有的 dnsmasq 配置我习惯单独建一个文件/etc/dnsmasq-wifi.conf启动时用-C指定interfacewlan0 bind-interfaces domain-needed bogus-priv no-resolv server223.5.5.5 server119.29.29.29 dhcp-range10.10.0.10,10.10.0.100,255.255.255.0,12h dhcp-option3,10.10.0.1 dhcp-option6,223.5.5.5,119.29.29.29 dhcp-leasefile/var/lib/misc/dnsmasq-wifi.leases解释几个容易被忽略的选项bind-interfaces只让 dnsmasq 监听 wlan0不监听其他接口。这能避免和系统里其他 DNS 服务抢端口特别是在 Debian 11 默认跑着 systemd-resolved 的情况下no-resolv不要读/etc/resolv.confDNS 上游固定用下面指定的server。否则一旦主机上游 DNS 变动热点客户端就跟着遭殃server223.5.5.5和server119.29.29.29国内公共 DNS。海外用户换成自己常用的公共 DNS 即可dhcp-range地址池 10.10.0.10 到 10.10.0.100子网掩码 255.255.255.0租约 12 小时dhcp-option3,10.10.0.1给客户端下发的默认网关dhcp-option6,...给客户端下发的 DNS 服务器。2.3 给热点单独规划网段别和上级网络撞车很多人图省事直接把热点网段设成192.168.1.0/24因为家里路由器经常是这个网段。但这会带来一个极其隐蔽的问题热点机器本身在192.168.1.0/24网段上网热点自己也用这个网段路由表会混乱甚至出现客户端必须通过上级网关才能访问到热点机器的诡异现象。我推荐用10.10.0.0/24、172.16.20.0/24这种不太常见的私有网段。配置静态 IP 这步非常关键而且 hostapd 不会自动帮网卡配 IP。启动热点前必须手动设置ip addr flush dev wlan0 ip addr add 10.10.0.1/24 dev wlan0 ip link set wlan0 up很多人忘了这步然后看到 dnsmasq 日志里报错no address range available for DHCP request其实就是 wlan0 上没 IPdnsmasq 不知道怎么分配网关。3. 把流量送上网NAT 转发与 iptables 规则3.1 开启内核 IP 转发热点客户端拿到 10.10.0.x 地址后要访问外网必须经过主机转发。Linux 默认不转发 IP 包先打开sysctl -w net.ipv4.ip_forward1想让重启后依然生效写进/etc/sysctl.d/99-hotspot.confnet.ipv4.ip_forward13.2 iptables 规则详解与持久化假设上行接口是 eth0需要加三条规则iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT第一条最重要它把从热点接口进来的、要从 eth0 出去的包源 IP 统一改写成 eth0 的 IP。相当于替热点客户端“伪装”成主机发出的流量。这里有个常见问题为什么不用-j SNAT --to-source指定固定 IP因为 eth0 的地址可能是 DHCP 动态获取的。MASQUERADE 每次自动取出口接口的当前 IP省得 IP 变了之后 NAT 规则失效。第二条允许 wlan0 里的客户端流量转发到 eth0第三条只允许 eth0 返回的、并且是热点客户端连接产生的回包进入 wlan0这样比直接放行全部 FORWARD 安全一点。持久化方面Debian 11 默认没装 iptables-persistent。可以装一下apt install -y iptables-persistent netfilter-persistent save不过我更喜欢把 iptables 规则直接写进后面的启动脚本里每次启动热点时重新执行一遍不依赖 netfilter-persistent 的恢复时机。3.3 从客户端视角验证链路通不通配置完 NAT 后先在热点机器上检查iptables -t nat -L POSTROUTING -n -v cat /proc/sys/net/ipv4/ip_forward然后让手机或另一台电脑连接热点按顺序做这几步看客户端拿到的 IP 是不是 10.10.0.x网关是不是 10.10.0.1从客户端 ping 10.10.0.1不通就是链路层或 DHCP 问题从客户端 ping 223.5.5.5通了说明 NAT 正常从客户端 ping baidu.com通了说明 DNS 正常。哪一步断了问题就定位到哪一层不用瞎猜。4. 用 systemd 把热点变成开机自启服务4.1 为什么要自己写服务而不是直接用系统默认服务Debian 安装 hostapd 时带了一个hostapd.service但它默认读取/etc/default/hostapd里的DAEMON_CONF不配置就会启动失败。dnsmasq 的系统服务也会读取/etc/dnsmasq.conf容易跟我的自定义配置冲突。所以最干净的办法是把它们都 mask 掉自己写一个启动脚本加 systemd 单元把网卡检查、IP 设置、hostapd、dnsmasq、iptables 这几件事按顺序管理起来日志和停止清理都能统一控制。4.2 启动脚本与 systemd 单元实例脚本我放在/usr/local/bin/wifi-hotspot.sh大概长这样#!/usr/bin/env bash set -euo pipefail IFACE_APwlan0 IFACE_UPeth0 AP_NET10.10.0.1/24 HOSTAPD_CONF/etc/hostapd/hostapd.conf DNSMASQ_CONF/etc/dnsmasq-wifi.conf HOSTAPD_PID/run/wifi-hotspot/hostapd.pid DNSMASQ_PID/run/wifi-hotspot/dnsmasq.pid start() { echo Starting WiFi hotspot... mkdir -p /run/wifi-hotspot rfkill unblock wifi || true nmcli device set $IFACE_AP managed no || true ip link set $IFACE_AP up ip addr flush dev $IFACE_AP ip addr add $AP_NET dev $IFACE_AP sysctl -w net.ipv4.ip_forward1 iptables -t nat -C POSTROUTING -o $IFACE_UP -j MASQUERADE 2/dev/null || \ iptables -t nat -A POSTROUTING -o $IFACE_UP -j MASQUERADE iptables -C FORWARD -i $IFACE_AP -o $IFACE_UP -j ACCEPT 2/dev/null || \ iptables -A FORWARD -i $IFACE_AP -o $IFACE_UP -j ACCEPT iptables -C FORWARD -i $IFACE_UP -o $IFACE_AP -m state --state RELATED,ESTABLISHED -j ACCEPT 2/dev/null || \ iptables -A FORWARD -i $IFACE_UP -o $IFACE_AP -m state --state RELATED,ESTABLISHED -j ACCEPT /usr/sbin/hostapd -B -P $HOSTAPD_PID $HOSTAPD_CONF sleep 2 /usr/sbin/dnsmasq -C $DNSMASQ_CONF --pid-file$DNSMASQ_PID echo Hotspot started. } stop() { echo Stopping WiFi hotspot... [ -f $DNSMASQ_PID ] kill $(cat $DNSMASQ_PID) 2/dev/null || true [ -f $HOSTAPD_PID ] kill $(cat $HOSTAPD_PID) 2/dev/null || true iptables -t nat -D POSTROUTING -o $IFACE_UP -j MASQUERADE 2/dev/null || true iptables -D FORWARD -i $IFACE_AP -o $IFACE_UP -j ACCEPT 2/dev/null || true iptables -D FORWARD -i $IFACE_UP -o $IFACE_AP -m state --state RELATED,ESTABLISHED -j ACCEPT 2/dev/null || true nmcli device set $IFACE_AP managed yes || true echo Hotspot stopped. } case ${1:-} in start) start ;; stop) stop ;; *) echo Usage: $0 {start|stop}; exit 1 ;; esac这个脚本有几个细节值得说明iptables -C先检查规则是否已存在避免重复添加hostapd 用-B转后台并指定 pid 文件dnsmasq 直接执行默认 daemon 模式不占用前台停止时先杀 dnsmasq 再杀 hostapd然后删除 NAT 规则恢复 NetworkManager 对网卡的管理。写好脚本后加执行权限chmod x /usr/local/bin/wifi-hotspot.sh然后创建 systemd 单元/etc/systemd/system/wifi-hotspot.service[Unit] DescriptionCustom WiFi Hotspot Service Wantsnetwork-online.target Afternetwork-online.target [Service] Typeoneshot RemainAfterExityes ExecStart/usr/local/bin/wifi-hotspot.sh start ExecStop/usr/local/bin/wifi-hotspot.sh stop [Install] WantedBymulti-user.target最后启用并启动systemctl daemon-reload systemctl enable --now wifi-hotspot.service systemctl status wifi-hotspot.serviceTypeoneshot配合RemainAfterExityes的意思是ExecStart执行完成后服务仍然保持 active直到你执行systemctl stop时才调用ExecStop。这样手动管理很方便。4.3 日志怎么看journalctl、tcpdump、iw热点出问题时别急着重启日志会告诉你答案。# 看自定义服务的运行日志 journalctl -u wifi-hotspot.service -f # hostapd 自身的详细日志启动时带 -d 更啰嗦 journalctl -u hostapd -f # 查看无线客户端关联情况 iw dev wlan0 station dump # 抓 DHCP 报文 tcpdump -i wlan0 port 67 or port 68 -n # 看 NAT 计数器是否在涨 iptables -t nat -L POSTROUTING -n -v这几条命令基本覆盖了从二层到四层的排查。如果发现 hostapd 起不来先手动前台跑一次killall hostapd || true hostapd -dd /etc/hostapd/hostapd.conf-dd会输出海量调试信息里面能看到是网卡不支持 AP、信道不可用还是密码策略冲突。5. 避坑实战客户端连上却上不了网网络图标消失怎么办5.1 现象网能上但 WiFi 连接符号不显示很多人在用 Windows 笔记本连接 Linux 热点时会遇到一个怪现象网页能打开QQ 微信都能用但任务栏的 WiFi 图标就是显示“无 Internet”或地球图标。“笔记本已连接热点也可以上网但不能正常显示wifi连接符号”这个问题根因通常是 Windows 的 NCSINetwork Connectivity Status Indicator探测失败。Windows 会向微软的服务器发起 HTTP 请求来判断网络是否可用如果热点侧的 NAT、DNS 配置不完整或者上游网络屏蔽了那个探测地址图标就会显示异常。这不算致命故障但很容易让人误以为热点坏了。解决方向有两个一是检查热点端 NAT 和 DNS 是否正常确保客户端能真正访问外网二是如果只是图标不显示但实际能上网那是 NCSI 探测被干扰调整热点 DNS 或上游网络后自然恢复。反过来如果手机也显示“已连接但无网络”那就不是图标问题大概率是链路真的不通。这时候按下面这套逻辑排。5.2 四层链路排查法从硬件到 DNS 一层层踩我总结了一张排障表基本覆盖了最常见的故障点。排查层常见现象关键命令可能原因链路层搜不到 SSID、连不上、频繁掉线iw list、iw dev wlan0 station dump、journalctl -u hostapd网卡不支持 AP、rfkill 封锁、信道不可用、驱动 bug网络层能连上但拿不到 IPjournalctl -u dnsmasq、tcpdump -i wlan0 port 67 or 68dnsmasq 没启动、wlan0 没配 IP、端口冲突路由/NAT能拿 IP 但出不了外网cat /proc/sys/net/ipv4/ip_forward、iptables -t nat -L -v没开转发、MASQUERADE 规则缺失、默认 FORWARD 策略是 DROP应用层能 ping 通 IP 但打不开网页dig short baidu.com 223.5.5.5、nslookupDNS 未下发、上游 DNS 不可达、no-resolv配置缺失奉劝一句不要一上来就怀疑 DNS。如果客户端根本 ping 不通网关查再久 DNS 也没意义。我见过有人折腾一整个晚上最后发现是 wlan0 上没配 IPdnsmasq 压根没起来。按表格自下而上五分钟就能定位。5.3 热点频繁掉线、连不上的硬件与配置坑掉线问题比“完全上不了网”更难缠下面这几个是我实际遇到过的坑。第一个是无线网卡的电源管理。笔记本自带网卡为了省电默认可能启用 power save导致热点模式下数据包延迟、丢包严重甚至掉客户端。处理方法是关掉iw dev wlan0 set power_save off建议把这句加进启动脚本的 start 逻辑里。第二个是 2.4GHz 频段里的信道拥堵。办公室、酒店这种地方 2.4GHz 基本是重灾区。手动把信道固定到 1、6、11 里最干净的那个或者干脆用 5GHz。但如果客户端是老旧手机或不支持 5GHz 的设备只能继续优化 2.4GHz 的参数。第三个是 5GHz 下的 DFS 信道问题。自动选频时 hostapd 可能选中 DFS 信道客户端一连接雷达检测一触发信道就跳表现为“连上就断、断了又连”。手动指定非 DFS 信道比如 149能直接绕开。第四个是 USB 网卡的供电。有些 USB 无线网卡插在 USB 2.0 口或者劣质 HUB 上发射功率不稳定客户端一多就掉。换 USB 3.0 口或者带独立供电的 HUB 试试成本最低但效果立竿见影。5.4 仓库版不够用从 hostapd 源码编译新版Debian 11 的软件仓库里 hostapd 版本通常够用但如果你想上 WPA3/SAE 个人加密或者遇到某些新网卡的兼容性 bug仓库版可能不太给力。从源码编译并不复杂apt install -y build-essential pkg-config libssl-dev libnl-3-dev libnl-genl-3-dev wget https://w1.fi/releases/hostapd-2.10.tar.gz tar -xf hostapd-2.10.tar.gz cd hostapd-2.10/hostapd cp defconfig .config然后编辑.config找到并启用CONFIG_SAEy CONFIG_IEEE80211Wy保存后编译安装make -j$(nproc) make install装完以后which hostapd大概率会指向/usr/local/sbin/hostapd。注意你的启动脚本里调用的是/usr/sbin/hostapd记得统一路径否则会出现“我明明编译了新版跑的还是旧版”的尴尬。6. 把整套流程封装成一个顺手的一键命令6.1 一个能日常使用的 wifi-hotspot 脚本文章前面已经给出脚本主体日常使用时你只需要把IFACE_AP、IFACE_UP换成自己的网卡名。如果上行口是wlan1把IFACE_UPwlan1如果上行口是ppp0iptables 里-o eth0也要改成-o ppp0。脚本的命名、路径都可以按习惯调整。使用方式/usr/local/bin/wifi-hotspot.sh start /usr/local/bin/wifi-hotspot.sh stop systemctl enable --now wifi-hotspot.service这一步做完整套热点方案就从一个“临时敲命令”的行为变成了一个“随用随开”的命令行工具。这也正是命令行工作流的乐趣先手工跑通再封装成脚本最后接入 systemd 自动管理。以后换机器把配置文件和脚本一拷两分钟就能复现。6.2 和 NetworkManager 和平共处如果你平时还需要用 wlan0 连接普通 WiFi而热点只是偶尔用那不要永久把 wlan0 设为 unmanaged。建议只在 start 脚本里临时设置nmcli device set wlan0 managed nostop 时再恢复managed yes就像我在脚本里写的那样。如果你的机器就是专门做热点的不想每次开机都等 NetworkManager 抢一下网卡可以在/etc/NetworkManager/NetworkManager.conf的[keyfile]段加上[keyfile] unmanaged-devicesinterface-name:wlan0这样 NetworkManager 完全不管 wlan0hostapd 启动时少一个竞争对手。但代价是这台机器的 wlan0 没法再用图形界面连 WiFi只适合纯热点或服务器场景。6.3 几个值得一试的扩展玩法热点稳定运行之后还可以加一些实用功能。MAC 白名单在/etc/hostapd/hostapd.conf里加macaddr_acl1 accept_mac_file/etc/hostapd/hostapd.accept/etc/hostapd/hostapd.accept每行写一个 MAC 地址例如AA:BB:CC:DD:EE:FF。这样只有白名单里的设备能连适合只给固定设备用热点的场景。DHCP 静态分配想让某台客户端每次拿同一个 IP在 dnsmasq 配置里加dhcp-hostAA:BB:CC:DD:EE:FF,10.10.0.99这个配合端口转发或内网服务时很好用。固定带宽如果担心某个客户端把带宽占满可以用tc做简单限速但这属于另一个话题了文章篇幅有限先挖个坑。在热点上线后我最常做的验证动作其实是看四件套hostapd 进程有没有存活、iw dev wlan0 station dump里有没有客户端、dnsmasq 日志里有没有 DHCP ACK、iptables -t nat -L POSTROUTING -v的计数器有没有在涨。这四个检查都通过热点基本就是稳的。对于那些“连上了但图标消失”的玄学问题先按四层表排查确认 NAT 和 DNS 都没问题之后就可以放心地把它归入“显示层误判”继续安心上网。最后再啰嗦一句热点密码一定要设足够强别开着 WPA2 还用一个八位纯数字密码毕竟任何人都可能搜到你的 SSID。