前言 #
解决异地亲人的多媒体影音需求,克服条件:
- 异地亲人没有维护服务器能力的;
- 本地和异地的上行带宽皆有限;
- 异地无公网;
- 尽可能不占用本地资源;
方法一 | Plex直接访问 #
在已有Plex服务的情况下,最直接的方法当然是在异地电视上安装Plex客户端访问,但受限于本地上行带宽低,异地电视配置差、且不支持HDR,实际测试效果并不理想。
方法二 | P2P文件传输 #
通过在异地安装轻量化服务器,并安装Jellyfin服务,用P2P传输媒体文件至异地。虽然传输慢,但观看过程是流畅的。这种方法可能会给本地宽带来较大负担,并且我担忧上行流量过大,引起运营商的关注(之前网上有过不少PCDN误判案例)。
方法三 | 混合 PT+P2P+异地组网 #
- 在家宽下行大、上行小的现状下,还是得依赖BT/PT实现文件的快速获取,查阅了几个PT站点的规则,发现有的站点也支持多IP下载,只要不同时下载同一个torrent即可(具体的规则需要谨慎研究各个PT站点规则,必要时向站点管理员询问或备案);
- 我同时保留了P2P的方案,以供非BT/PT的大文件传输和torrent文件的同步;
- 由于异地宽带无公网IP,亲人也没有足够的网络知识来维护异地服务器,所以要在
本地(城市1)
实现对异地(城市2)
的管理,需要设计一个自动化的异地组网方案。我在本地(城市1)
开启一个Webhook,异地(城市2)
设置轮询,通过在本地设置Webhook的应答,异地自动加入/离开组网(自动离开非常重要,避免占用本地(城市1)
宽带资源);
如图所示,本地(城市1)
是一个X86架构服务器,异地(城市2)
是一个树莓派5,城市x
则是任意一台终端设备;通过wireguard实现异地组网,组网内的设备可以相互访问、管理。树莓派5装有Jellyfin、rtorrent、resilio软件,具体的设置过程在下一章节详解。多媒体文件的获取以PT为主,Resilio为辅,PT通过flood&rtorrent客户端管理,rtorrent下载任务可以由rss、torrent文件触发。
Raspberry Pi OS 设置 #
根据官方方法将Raspberry Pi OS烧录进树莓派后,即可开始以下配置。
必要设置 #
- 开启ssh;
sudo service ssh start
sudo systemctl enable ssh # 开机自启动
- 安装Docker, Debian | Docker Docs
- 安装Vim:
sudo apt install vim
- 换源:
sudo vim /etc/apt/sources.list
:
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm main contrib non-free non-free-firmware
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm main contrib non-free non-free-firmware
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware
deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-backports main contrib non-free non-free-firmware
# deb-src https://mirrors.tuna.tsinghua.edu.cn/debian/ bookworm-backports main contrib non-free non-free-firmware
# 以下安全更新软件源包含了官方源与镜像站配置,如有需要可自行修改注释切换
deb https://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
# deb-src https://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
Flood | Torrent下载器 #
- 新建必要文件夹
mkdir flood
cd flood
mkdir config media
vi docker-compose.yml
docker-compose.yml
配置
# docker-compose.yml
services:
flood:
image: jesec/flood
user: 1000:1001
restart: unless-stopped
command: --port 3001 --allowedpath /data
environment:
HOME: /config
volumes:
- ./config:/config
- ./media:/data/media
ports:
- 3001:3001
rtorrent:
image: jesec/rtorrent
user: 1000:1001
restart: unless-stopped
command: -o network.port_range.set=16888-16888,system.daemon.set=true,dht.mode.set=disable
environment:
HOME: /config
volumes:
- ./config:/config
- ./media:/data/media
ports:
- 16888:16888
- 运行容器
sudo docker compose up -d
- 访问
http://RASPBERRY_IP_ADDRESS
,在设置界面,连接类型
选择Socket
,Socket内容填写~/.local/share/rtorrent/rtorrent.sock
- 设置界面
默认下载位置
修改为/data/media
; - 检查确认
DHT
、节点交换
为关闭状态; - (可选)点击rss图标,可以使用PT站点提供的rss链接实现自动下载;
Resilio Sync | P2P同步 #
- Package: https://help.resilio.com/hc/en-us/articles/206178924
- 下载
DEB arm64
安装包; - 安装
sudo dpkg -i <resilio-sync.deb>
- 访问
http://YOUR_RASPBERRY_IP:8888
完成设置; - 开机自启动,
sudo systemctl enable resilio-sync
- 设置同步文件夹,如该文件夹为用户
raspberry
所有,确保rslsync
权限足够:
ls -ld /YOUR_SYNC_FOLDER
# drwxr-xr-x 2 raspberry raspberry 4096 YOUR_SYNC_FOLDER
# 更改权限
sudo chmod 777 YOUR_SYNC_FOLDER -R
- 新建同步文件夹,
标准文件夹
,高级文件夹
均可,完成后共享权限改成读写
,将链接复制到服务端输入密钥或链接
完成设置; - (可选,预定义同步主机)服务端可将Resilio的端口映射至路由进而在公网开放,在树莓派端,选择共享链接的
首选项
->预定义主机
->填入服务端网址和端口即可; - 通过Resilio Sync实现自动自动导入种子开始下载:将路径
/home/raspberry/project/flood/config/.local/share/rtorrent/watch
建立同步。完成后,只需将种子文件放入/watch/start
文件夹中,rtorrent将自动开启下载任务,将种子文件放入/watch/load
文件夹中,rtorrent将自动新建下载任务(但不开始下载);
Jellyfin | 多媒体服务器 #
- Site: Jellyfin
curl -s https://repo.jellyfin.org/install-debuntu.sh | sudo bash
systemctl status jellyfin
# 打印状态为 Active: active (running)
-
http://RASPBERRY_IP_ADDRESS:8096
,按照指示完成设置; -
文件夹权限:
find ./project/ -exec ls -ld {} \;
sudo -u jellyfin ls /home/raspberry/project/media
# "ls: cannot access '/home/raspberry/project/media': Permission denied"
cd /home
sudo chmod 755 -R raspberry/ #raspberry为用户名称
Wireguard | 异地组网 #
本地(城市1) | Server #
- 安装Wireguard,根据提示一步一步完成配置;
curl -O https://raw.githubusercontent.com/angristan/wireguard-install/master/wireguard-install.sh
chmod +x wireguard-install.sh
./wireguard-install.sh
- 将配置过程中选择的端口
port
映射至公网; - 生成的配置文件:
~/wg0-client-YOUR_WG_NAME.conf
;
[Interface]
PrivateKey = <你的私钥>
Address = 192.168.1.2/24 # 替换为分配的 IP 地址
DNS = 8.8.8.8 # 可选,设置 DNS 服务器
[Peer]
PublicKey = <服务器的公钥>
Endpoint = <服务器的IP或域名>:<端口号>
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
异地(城市2) | Client #
- 安装Wireguard;
sudo apt update
sudo apt install wireguard -y
- 将服务端生成的
~/wg0-client-YOUR_WG_NAME.conf
内容填入以下路径文件中;
sudo vim /etc/wireguard/wg0.conf
- 启动;
# 启动连接
sudo wg-quick up wg0
# 验证连接
sudo wg show
ping 10.0.0.1 # Ping 服务端的内部 IP 地址(例如 10.0.0.1)
curl ifconfig.me # 应该显示服务端外部 IP
# 关闭连接
sudo wg-quick down wg0
- 若遇到
/usr/bin/wg-quick: line 32: resolvconf: command not found
sudo apt install resolvconf -y
- 若安装resolvconf后无法解析域名
sudo vim /etc/resolv.conf
# 确保其中有一个有效的 nameserver 条目,如nameserver 8.8.8.8,否则手动添加
轮询 #
- 在服务端设置一个webhook,我用的是n8n,也可以使用adnanh/webhook或flask构建。用Response Code来控制树莓派客户端是否开启Wireguard(
200
为连接,201
为断开连接)。 - 为避免违反PT规则,开启wireguard前关闭rtorent任务,轮询脚本如下:
# /home/raspberry/project/wireguard_poller.py
import os
import time
import requests
import logging
WEBHOOK_URL = "https://xxxx.xxx"
wg_active = False
LOG_FILE = "/var/log/wireguard_poller.log"
DOCKER_CONTAINERS = ["flood-flood-1", "flood-rtorrent-1"]
logging.basicConfig(
filename=LOG_FILE,
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
def manage_docker_containers(action):
for container in DOCKER_CONTAINERS:
try:
logging.info(f"{action.capitalize()}ing Docker container: {container}...")
os.system(f"sudo docker {action} {container}")
logging.info(f"Container {container} {action}ed successfully.")
except Exception as e:
logging.error(f"Failed to {action} container {container}: {e}")
def toggle_wireguard(enable):
global wg_active
if enable and not wg_active:
logging.info("Stopping Docker containers before starting WireGuard...")
manage_docker_containers("stop")
logging.info("Starting WireGuard service...")
os.system("sudo wg-quick up wg0")
wg_active = True
logging.info("WireGuard service started.")
elif not enable and wg_active:
logging.info("Stopping WireGuard service...")
os.system("sudo wg-quick down wg0")
wg_active = False
logging.info("WireGuard service stopped.")
logging.info("Starting Docker containers after stopping WireGuard...")
manage_docker_containers("start")
def poll_webhook(interval):
global wg_active
while True:
try:
logging.info(f"Polling {WEBHOOK_URL}...")
response = requests.get(WEBHOOK_URL, timeout=10)
logging.info(f"Response code: {response.status_code}")
if response.status_code == 200:
toggle_wireguard(True)
interval = 60
elif response.status_code == 201:
toggle_wireguard(False)
interval = 300
except requests.exceptions.RequestException as e:
logging.warning(f"Request failed: {e}")
time.sleep(interval)
def main():
try:
logging.info("Starting webhook poller...")
poll_webhook(interval=300)
except KeyboardInterrupt:
logging.info("Exiting...")
finally:
if wg_active:
toggle_wireguard(False)
if __name__ == "__main__":
main()
- 创建 systemd 服务;
# sudo vim /etc/systemd/system/wireguard_poller.service
[Unit]
Description=WireGuard Poller Service
After=network.target
[Service]
ExecStart=/usr/bin/python /home/raspberry/project/wireguard_poller.py
Restart=always
User=root
[Install]
WantedBy=multi-user.target
- 启用;
sudo systemctl daemon-reload
sudo systemctl enable wireguard_poller.service
sudo systemctl start wireguard_poller.service
- 查询日志
cat /var/log/wireguard_poller.log
;
管理和使用 #
- 树莓派的Wireguard连上服务器后,在服务端
sudo wg show
可以看到连接状态和局域网ip,如10.66.66.2
; - 重复使用
./wireguard-install.sh
为另一台任意设备(PC或移动设备)创建连接,即可访问树莓派的服务了,如Flood10.66.66.2:3001
,Jellyfin10.66.66.2:8096
,Resilio10.66.66.2:8888
; - 可在任意组网终端使用SSH连接管理树莓派
ssh [email protected]
; - 可在任意终端使用resilio上传种子文件至
/watch
文件夹中,自动触发下载任务; - 可任意终端使用resilio上传多媒体文件至Jellyfin监控的文件中;