最开始纠结是 PVE 还是直接跑 Linux ,但是想了一下都 all in one 了干脆直接 Linux 省的套娃。
最后整体思路:
小黄鱼淘了一台 4 网口的 AMD 主板,16G 内存,CPU 型号忘了,看了一下是 es 的,无所谓了
root@shawn-aio:~# grep name /proc/cpuinfo | cut -f2 -d: | uniq -c
4 AMD Eng Sample
root@shawn-aio:~# free -h
total used free shared buff/cache available
Mem: 14Gi 1.9Gi 9.8Gi 200Mi 3.4Gi 12Gi
Swap: 4.0Gi 0B 4.0Gi
eno1 做 wan 口,通过 iptables nat 表做 masquerade 给内部提供外网访问能力。wan 口只开放 vpn 端口。
iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE
root@shawn-aio:~# iptables -S INPUT
-P INPUT DROP
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i br-mgmt -j ACCEPT
-A INPUT -i eno1 -p udp -m udp --dport 51820 -j ACCEPT
-A INPUT -i wg0 -j ACCEPT
-A INPUT -i lxcbr0 -j ACCEPT
-A INPUT -i br-0ad574e582c7 -j ACCEPT
-A INPUT -i nerdctl0 -j ACCEPT
创建 br-mgmt ,接入 enp3s0 ,enp4s0 ,enp5s0 做 lan 口,同时通过 veth 将 netns gateway 接到 br-mgmt ,并在 netns 中提供 dhcp ,下发默认路由和 dns 地址。
root@shawn-aio:~# ip a show br-mgmt
6: br-mgmt: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether ea:a4:3d:6c:ce:d0 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.254/24 brd 172.20.0.255 scope global br-mgmt
valid_lft forever preferred_lft forever
inet6 fe80::e8a4:3dff:fe6c:ced0/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
root@shawn-aio:~# ip netns exec gateway ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host proto kernel_lo
valid_lft forever preferred_lft forever
12: gTb@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 52:ef:a4:d0:0c:e9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.20.0.1/24 scope global gTb
valid_lft forever preferred_lft forever
inet6 fe80::50ef:a4ff:fed0:ce9/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
root@shawn-aio:~# ip l show master br-mgmt
3: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br-mgmt state UP mode DEFAULT group default qlen 1000
link/ether 20:76:93:5b:14:4f brd ff:ff:ff:ff:ff:ff
4: enp4s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel master br-mgmt state DOWN mode DEFAULT group default qlen 1000
link/ether 20:76:93:5b:14:50 brd ff:ff:ff:ff:ff:ff
5: enp5s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel master br-mgmt state DOWN mode DEFAULT group default qlen 1000
link/ether 20:76:93:5b:14:51 brd ff:ff:ff:ff:ff:ff
13: bTg@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-mgmt state UP mode DEFAULT group default qlen 1000
link/ether aa:36:50:e4:db:81 brd ff:ff:ff:ff:ff:ff link-netns gateway
15: veth18XBnR@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-mgmt state UP mode DEFAULT group default qlen 1000
link/ether fe:e5:47:3f:90:3b brd ff:ff:ff:ff:ff:ff link-netnsid 1
16: vethdxnWc4@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-mgmt state UP mode DEFAULT group default qlen 1000
link/ether fe:c1:4c:94:06:ba brd ff:ff:ff:ff:ff:ff link-netnsid 2
root@shawn-aio:~# systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Fri 2025-05-09 08:38:57 CST; 1 week 0 days ago
Invocation: a6039cd62e984eb0bd649511a52f5060
Docs: man:nginx(8)
Main PID: 6945 (nginx)
Tasks: 5 (limit: 17733)
Memory: 8.6M (peak: 13.6M)
CPU: 1.111s
CGroup: /system.slice/nginx.service
├─6945 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
├─6946 "nginx: worker process"
├─6947 "nginx: worker process"
├─6948 "nginx: worker process"
└─6949 "nginx: worker process"
May 09 08:38:57 shawn-aio systemd[1]: Starting nginx.service - A high performance web server and a reverse proxy server...
May 09 08:38:57 shawn-aio systemd[1]: Started nginx.service - A high performance web server and a reverse proxy server.
自己写了个脚本,创建了一个 netns 后,在 netns 中跑 dnsmasq 提供 dhcp 服务。里面跑 clash ,并设置 iptables 规则来实现透明代理。
root@shawn-aio:~# systemctl status gateway
● gateway.service - Gateway service enable tproxy
Loaded: loaded (/etc/systemd/system/gateway.service; enabled; preset: enabled)
Active: active (running) since Fri 2025-05-09 08:38:57 CST; 1 week 0 days ago
Invocation: 76718511daa5473bad8931fedd4d54c9
Main PID: 6873 (gateway.sh)
Tasks: 3 (limit: 17733)
Memory: 5.1M (peak: 6.8M)
CPU: 1d 22h 47min 56.956s
CGroup: /system.slice/gateway.service
├─6873 /usr/bin/bash /opt/gateway/gateway.sh start
├─6973 /usr/sbin/dnsmasq -C /opt/gateway/dnsmasq.conf
└─6974 bash /opt/gateway/tproxy.sh start
May 15 08:25:45 shawn-aio dnsmasq-dhcp[6973]: DHCPREQUEST(gTb) 172.20.0.165 c8:a3:62:57:df:69
May 15 08:25:45 shawn-aio dnsmasq-dhcp[6973]: DHCPACK(gTb) 172.20.0.165 c8:a3:62:57:df:69 luchengdeMBP
May 15 13:53:13 shawn-aio dnsmasq-dhcp[6973]: DHCPREQUEST(gTb) 172.20.0.165 c8:a3:62:57:df:69
May 15 13:53:13 shawn-aio dnsmasq-dhcp[6973]: DHCPACK(gTb) 172.20.0.165 c8:a3:62:57:df:69 luchengdeMBP
May 15 19:10:29 shawn-aio dnsmasq-dhcp[6973]: DHCPREQUEST(gTb) 172.20.0.165 c8:a3:62:57:df:69
May 15 19:10:29 shawn-aio dnsmasq-dhcp[6973]: DHCPACK(gTb) 172.20.0.165 c8:a3:62:57:df:69 luchengdeMBP
May 16 00:33:54 shawn-aio dnsmasq-dhcp[6973]: DHCPREQUEST(gTb) 172.20.0.165 c8:a3:62:57:df:69
May 16 00:33:54 shawn-aio dnsmasq-dhcp[6973]: DHCPACK(gTb) 172.20.0.165 c8:a3:62:57:df:69 luchengdeMBP
May 16 06:08:01 shawn-aio dnsmasq-dhcp[6973]: DHCPREQUEST(gTb) 172.20.0.165 c8:a3:62:57:df:69
May 16 06:08:01 shawn-aio dnsmasq-dhcp[6973]: DHCPACK(gTb) 172.20.0.165 c8:a3:62:57:df:69 luchengdeMBP
root@shawn-aio:~# ip netns
gateway (id: 0)
使用场景很简单,感觉没必要用 tailscale 或者 netmaker 。同时自己不太喜欢界面,所以自己模仿 wg-easy 写了个 wg 服务来提供 VPN 服务。客户端直接鉴权是模仿 k8s apiserver 和 kubectl 通过 tls 证书鉴权。
root@shawn-aio:~# wgctl subnet list
UUID Name Address Public Key
e4212eda-233f-11f0-8903-2076935b144e default 10.67.0.1/24 <pub key>
root@shawn-aio:~# wgctl peer list -s e4212eda-233f-11f0-8903-2076935b144e
UUID User Address Public Key Enable
f9615f20-233f-11f0-8903-2076935b144e lucheng 10.67.0.2/24 <pub key> true
root@shawn-aio:~# wg
interface: wg0
public key: <server pubkey>
private key: (hidden)
listening port: 51820
peer: <peer pubkey>
endpoint: 10.28.66.18:36303
allowed ips: 10.67.0.2/32
latest handshake: 29 minutes, 23 seconds ago
transfer: 5.14 MiB received, 35.12 MiB sent
lxc 跑 ubuntu 在里面装 jellyfin
root@shawn-aio:~# lxc-ls -f
NAME STATE AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED
jellyfin RUNNING 1 - 172.20.0.2 - false
ubuntu RUNNING 1 - 172.20.0.3 - false
root@shawn-aio:~# nerdctl ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
05a100ce77d8 quay.io/shawnlu0127/immich/immich-server:v1.131.1 "tini -- /bin/bash s…" 6 days ago Up 0.0.0.0:2283->2283/tcp immich_server
414297ba5e5f quay.io/shawnlu0127/immich/postgres:pg14-v0.2.0 "docker-entrypoint.s…" 6 days ago Up immich_postgres
6fa52ce3d9e1 quay.io/shawnlu0127/immich/redis:6.2-alpine "docker-entrypoint.s…" 6 days ago Up immich_redis
1
Angus007 5 天前
手搓大神 牛批
|
2
kid1412621 5 天前 via iPhone
为啥 lxc ? 不用 docker ?减少套一层?
|
![]() |
3
M48A1 5 天前 via iPhone
牛逼,刚准备换掉 Me mini ,弄个小主机上飞牛;
在纠结用 PVE 搭平台,还是直接飞牛,之前也打算直接 Linux ; 点赞! |
![]() |
4
gunner168 5 天前
jellyfin 不好用,要么字幕出问题,要么强制转码,要么直接播放不了,不如用飞牛,影视功能比 jelly 好多了,搜刮功能也很牛
|
5
lucheng0127 OP @kid1412621 docker 用 bridge 不能设置静态 ip
另外 lxc 相对于 docker ,我觉得 docker 更适合跑存服务,就像我的 immich lxc 适合做轻量化虚拟机,只是和容器一样隔离性差点 为了减少一层,所以用的 containerd+nerdctl |
6
lucheng0127 OP |
7
lucheng0127 OP @M48A1 其实 pve 管理挺方便的,而且有监控,之前用的时候感觉不错,
不过我感觉还是直接 linux 省事一点,不用查 pve 的文档和 issue |
![]() |
8
FlytoSirius 5 天前 via iPhone ![]() 和你一样,我也是尝试过各种 nas 系统之后, 选了 linux 自建, 但后来又经过一阵子测试发现:omv 是在 “linux 自建” 与 “沉重的 nas 系统”之间一个很恰当的平衡! 既有足够的控制,又不会过于繁杂。
所以, 你这种需求,强烈推荐你尝试 omv 系统。 |
9
ajaxgoldfish0 5 天前
@FlytoSirius 折腾到最后还是发现大道至简。
|
10
ajaxgoldfish0 5 天前
大道至简
|
![]() |
11
reeco 5 天前
Debian 插满硬盘装上 zfs samba 和 syncthing 就搞定了
|
13
allplay 5 天前 via Android
@FlytoSirius 基于 Debian , 手搓自建,再做一套 UI ,恭喜你,这就是 omv 。
|
14
Co1e 5 天前
手搓🐮
|
![]() |
15
neilxu 5 天前
我也是手搓的,i38100t+z370+16t+10t+4t+1tssd
pve 上,nas 是 debian12 ,另外暂时建了 5 个做 k8s 测试集群。 相册试了一堆都不理想,买的 mtphoto 很好。 vpn 用华硕官方.com 用 UI 的就是 kodbox 、plex 、qb 、tr ,其他的就是命令行。 |
![]() |
16
yautou 5 天前
|
![]() |
17
nerkeler 5 天前 via Android
后面几个有相同的需求,我用的 docker 跑的 nextcloud xunlei jellyfin
|
18
Laysan 5 天前
|
![]() |
19
Kinnice 5 天前
推荐迁移到 pve ,然后用 lxc 来搞,这样后续扩容和备份还原都很方便。
|
![]() |
20
defunct9 5 天前
懒得折腾了,兄弟给个不在 ns 里,只有一个网口朝外,dnsmasq 提供 dhcp ,mihomo 代理的方案吧。 @lucheng0127
|
21
lucheng0127 OP @defunct9 那直接执行这个脚本就可以了
https://github.com/lucheng0127/gateway/blob/main/scripts/tproxy.sh 需要提前创建 clash 用户 dnsmasq 里面 dist 目录下也有配置 sample |
![]() |
22
gunner168 5 天前
@lucheng0127 主要是客户端支持不好,我主要是在电视上看的,有好些片子播放不了,而且用起来比较卡,远不如飞牛影视的电视端好用
|
23
bjfane 5 天前
本来我是想来交流的, 看完楼主的内容,我是来学习的,哈哈哈🐶
|
![]() |
24
ShineyWang 5 天前
@Laysan PVE 的 tag 标记 就是带颜色的点可以设置成显示名称
这样可以显示 IP |
25
crazywenf 5 天前
手搓大神就是猛
|
26
lazinesssheep 4 天前
包装一下就是新的 nas 系统
|
![]() |
27
lozzow 4 天前
我是直接上了一个 k8s
|
![]() |
28
huangmingyou 4 天前
我的方案和 up 类似,但是虚拟化是 docker, 看视频,我直接用 samba 共享给 kodi
|
![]() |
29
wang9571 4 天前
请问媒体文件是怎么挂载到 jellyfin lxc 容器的?我用特权容器挂载宿主机文件夹,硬件转码时 io 延迟指标会高
|
30
kekylin 4 天前 ![]() 我也是使用 Debian 手搓方案,已经稳定使用好几年了。大道至简,用久了还是喜欢这种,功能可以按自己需求部署,像搭积木一样,很有乐趣。
为此我还在 Github 上建了相关项目分享经验,感兴趣的可以看看。 项目地址: https://kekylin.github.io/debnas-docs/ ![]() |
31
lucheng0127 OP @wang9571 IO 延迟高具体什么原因还真不知道,我的配置是这样的
lxc.mount.entry = /data/Jellyfin data no bind,create=dir 0 0 |
32
lucheng0127 OP @kekylin 你这个是真的做的很全面,厉害
|
![]() |
33
Kaiyuan 4 天前
最开始我也想自建,但是因为不是我自己一个用,家人也用,最后还是黑裙简单易用!然后就用了好多年。
|
![]() |
34
dabaibai 4 天前
手搓太容易 boom 。。。不推荐
|
![]() |
35
plko345 4 天前 via Android
@lucheng0127 docker 命令不知道,但 docker compose 可以设置静态 ip ,我也用 nerdctl 管理 compose 文件,更轻量
|
36
chnsatan 4 天前
手搓太容易折腾挂了~~
喜欢折腾的另说 |
38
chenbin36255 4 天前
pve+RR 引导+黑裙+直通 SATA 用了 2 年了 很稳
RR 可以更新,基本可以升到最新版 |
![]() |
39
takanashisakura 4 天前
曾经手搓过,3 年后的现在迁移到 PVE 了。但内部实际上还是分开的:应用跑在 docker 虚拟机,纯 nas 功能在 TrueNas 虚拟机。。。
|
40
kid1412621 4 天前
@lucheng0127 #5 jellyfin 不是服务吗?我本来在 Linux 上直接跑的,奈何 Fedora build 更新慢,不支持自定义 ffmpeg 之类的,直接用了容器版
|
41
lucheng0127 OP @kid1412621 是的,只是因为当时 docker 跑的时候没法通过 bridge 固定 ip ,所以才 lxc 跑的
|
![]() |
42
LindsayZhou 3 天前 via Android
|
![]() |
43
ragnaroks 3 天前
我也是直接上 debian ,从 debian 10 一直用到现在,还装了个 i3wm 当 GUI
|
44
lucheng0127 OP @ragnaroks i3wm 好评 O(∩_∩)O
|
![]() |
45
ragnaroks 3 天前
@lucheng0127 就它占用最小了,和 cockpit 那一坨相近
|
46
kid1412621 3 天前 via iPhone
@LindsayZhou #42 和软路由啥关系,我用 fedora 也遇到了
|
47
kid1412621 3 天前 via iPhone
@LindsayZhou #42 话说 docker 直接支持 nftables 的 issue 放了几年了…
|
![]() |
48
LindsayZhou 3 天前 via Android ![]() @kid1412621 #46 软路由上要做 nat ,要做透明代理,再跑 docker ,规则不会乱吗?
挺担心容器间的网络互通隔离的规则会失效。 再说如果需要改条啥规则,还要单独重启一下 docker 让它再把容器的规则加上 |
49
kid1412621 2 天前 via iPhone
@LindsayZhou #48 没在软路上放太多东西,主要跑 docker 的放到 Linux 上
|
![]() |
50
zyq2280539 2 天前
一直在用 ubuntu server 做服务器系统,软路由感觉最好单独放在一个硬件上,要不然很容易出问题
|
51
wolonggl 2 天前
@LindsayZhou 软路由上跑 docker 会引起一些莫名其妙的问题,比如 ipv6 lan 的设备无法上网,每次都反复折腾
|
![]() |
52
SakuraYuki 2 天前
@lucheng0127 #41 可以用 macvlan 实现静态 ip 吧
|
![]() |
53
SakuraYuki 2 天前
@gunner168 #4 刮削都是基于 tmdb 数据的,无非就是飞牛内置了个大模型来识别文件名,这些都能手搓出来
|
54
lucheng0127 OP @SakuraYuki macvlan 虽然虚拟化更轻量,但是子接口和父接口无法直接通信,用着稍微有点不方便
|
55
lucheng0127 OP @zyq2280539 其实在 netns 里面还好,性能和独享硬件差不多😂
然后网络环境也是隔离的 嘿嘿 |
![]() |
56
SakuraYuki 2 天前
@lucheng0127 #54 我是搞了个 macvlan 网桥来让独立 ip 的容器和其他容器通信的,然后开机脚本自启,不过这样缺点就是要占掉 2 个 ip
|
![]() |
59
molezznet 1 天前
armbian 或 pve + lxc
|
60
Senorsen 1 天前
跟我 10 年前( 2014-2017 )上大学时的方案简直一模一样呀,我是用 Ubuntu Linux 宿主机挂载机械硬盘当 NAS 存储,里边一个 lxc 写一堆 iptables 脚本+dnsmasq 规则+各种 VPN+ ss-redir 和 iptables-geoip 条件转发等等作为软路由。不过后来发现,OpenWrt 配置各种防火墙区域、规则、VPN 、静态路由、翻墙更省心,ipv6 在不同区域特殊的 input/forward 规则也不需要自己操心;群晖这种成品 NAS 系统图形界面配置各种共享、用户、配额、RAID 真省心…( ps 只对我自己而言,因为我是懒人,脚本堆多了很乱懒得收拾)
|
61
Senorsen 1 天前
@Senorsen 噢,仔细一看,并没有一模一样,只是类似( iptables 规则,dnsmasq ,多个 bridge 网桥和物理/虚拟接口,透明代理等,vpn -- 当年一开始是 ovpn ,随后 wg )。。
|
62
lucheng0127 OP @Senorsen 之前用过一下 openwrt 感觉里面的配置不太熟悉,因为本身工作方向可能对直接 linux 命令熟悉一些,所以就自己配置了😂
不过有 UI 和各种插件确实很方便 |
63
anonymity 1 小时 47 分钟前
我选择直接 PVE 起 LXC OpenWrt 和群晖虚拟机。。
|