proxmox安装ubuntu+openwrt全过程记录
大致思路
年青的时候不懂,为软路由安排了严重过剩的配置:
3865u 工控机,4g ddr4 2666 (实际cpu仅支持2133),msata 固态128g.. 全铝合金无风扇散热、工业级防尘设计 /
因为amazon ec2 免费实例的性能非常底下,且硬盘仅10g,用来部署后端服务非常吃力,于是想到将性能严重过剩的软路由重新设计为:使用proxmox做基系统,使用虚拟机安装openwrt和ubuntu系统。
前戏准备
安装pve
✅ 一、准备工作
下载 Proxmox VE 安装镜像
- 官方下载地址:
👉 https://www.proxmox.com/en/downloads/category/iso-images-pve
推荐版本:Proxmox VE 8.x(基于 Debian 12)
- 官方下载地址:
准备 U 盘启动盘
- U 盘大小:建议 ≥ 2GB
- 制作启动盘工具:
- Rufus(Windows):https://rufus.ie/zh/ (已验证免费)
- balenaEtcher(Mac/Linux 也可用):https://www.balena.io/etcher/
备份重要数据
- Proxmox 会清空整块硬盘安装系统,请确认磁盘已备份或空盘。
✅ 二、安装步骤(图形化安装)
启动安装器
- 将写好 Proxmox 的 U 盘插入电脑
- 开机按
F2/F10/ESC/Delete进入 BIOS,设置 U盘启动
坑爹预警!!也许是工控机主板比较老,当安装完毕后,重启机器后,会立刻检测usb键盘设备,如没有检测到(例如廉价9.9包邮键盘),直接卡死在开机前的阶段,并不会正常的进入系统,导致在工作台上无数次测试均正常,移至机房却N多次启动失败。
这是最终在工作台前的反复测试中,意外发现的此规律!!
应该会记住此次教训!毕竟9.9包邮的廉价键盘,在bios阶段根本无法正常被识别!!
后来经过验证,在 bios 阶段,9.9 键盘其实可以被识别并操作,但是一旦进入 pve 系统,仍然花屏+报错..
直到连上机械盘才得以解决问题。
- 启动后看到
Install Proxmox VE,选择回车继续
安装向导步骤
| 步骤 | 设置项 | 说明 |
|---|---|---|
| 第一步 | 同意协议 | 点击“我同意” |
| 第二步 | 选择磁盘 | 选中你的 SSD(通常是 /dev/sda) |
| 第三步 | 设置国家/时区/键盘 | 设置为 Asia/Shanghai 或你所在地区 |
| 第四步 | 设置管理员密码 | 用于 Web UI 登录,不可丢失 |
| 第五步 | 设置网络 | 推荐设置固定 IP,或 DHCP(后续也能修改) |
安装完成后重启
- 拔掉 U 盘
- 系统会自动进入 Proxmox 管理界面
proxmox的清华大学源
✅ 步骤一:确认当前 Proxmox 使用的是哪个源
你可以运行下面的命令来列出所有启用的源:
grep -r ^deb /etc/apt/ |
然后得到:
root@proxmox:~# grep -r ^deb /etc/apt/ |
这说明:
🔍 当前使用情况总结:
| 文件 | 当前内容 | 建议 |
|---|---|---|
/etc/apt/sources.list | Debian 官方主源:ftp.debian.org 和 security.debian.org | ✅ 可改为清华镜像,加快速度 |
/etc/apt/sources.list.d/pve-enterprise.list | Proxmox 企业源(需订阅) | ❌ 建议禁用(否则 apt 会报 401 错误) |
/etc/apt/sources.list.d/ceph.list | 企业版 Ceph 源 | ❌ 同样不适用于无订阅用户 |
✅ 接下来你可以这样操作:
✅ 第一步:禁用企业源
mv /etc/apt/sources.list.d/pve-enterprise.list /etc/apt/sources.list.d/pve-enterprise.list.disabled |
然后,可以直接用命令写入文件,避免格式问题:
cat << EOF > /etc/apt/sources.list |
以及,更改的 Proxmox VE 的“无订阅”(社区免费版)软件源:
echo "deb https://mirrors.tuna.tsinghua.edu.cn/proxmox/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-no-subscription.list |
二者针对的是 不同的软件源类型,它们各自负责系统中不同的软件包管理:
| 操作命令 | 作用对象 | 说明 |
|---|---|---|
修改 /etc/apt/sources.list | Debian 操作系统主源 | 负责管理系统底层软件和通用依赖包,保证 Debian 系统核心和常用软件包的安装和更新。 你改成清华镜像是为了加速和稳定访问。 |
修改 /etc/apt/sources.list.d/pve-no-subscription.list | Proxmox VE 专用源(社区免费版) | 负责管理 Proxmox VE 特有的软件包和功能(虚拟化管理工具等)。 无订阅用户使用该社区源,且改为清华镜像加速下载。 |
简单理解:
- Debian 源 是系统“基础包”的来源,类似操作系统的软件仓库
- Proxmox 源 是专门针对 Proxmox 虚拟化环境的软件仓库
两者都需要配置正确,系统才能既保持稳定的 Debian 基础环境,也能正常获取 Proxmox 相关软件更新。
完成后执行:
apt update |
确认无报错后就配置好了。
ubuntu的清华大学源
点击查看详情
长期支持版本:https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/
安装完成后,需要更改软件源,步骤如下:
✅ 更换为清华源的步骤(Ubuntu 22.04)
你可以按以下步骤操作:
- 备份原有源列表
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak |
- 编辑源列表文件
使用 nano(或你喜欢的编辑器):
sudo nano /etc/apt/sources.list |
- 替换为清华源内容(适用于 Ubuntu 22.04 “jammy”)
将内容全部替换为以下内容:
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse |
由于不好粘贴,可以这样:
sudo tee /etc/apt/sources.list > /dev/null << EOF |
这样就一步到位了!!
- 更新软件列表
sudo apt update |
开始折腾
点击查看详情
到这里,就可以使用 finalshell 登录了,因为之前从github拉取了公钥,需要携带私钥进行登录。
先安装个lychee图床试试:
先安装docker:
sudo apt update
sudo apt install docker.io配置docker镜像源
步骤1:创建配置文件
sudo mkdir -p /etc/docker
sudo vim /etc/docker/daemon.json步骤2:添加镜像源(推荐)
sudo tee /etc/docker/daemon.json > /dev/null <<EOF
{
"registry-mirrors": ["https://docker.xuanyuan.me"]
}
EOF步骤3:重启服务
sudo systemctl daemon-reload
sudo systemctl restart docker然后,运行以下命令:
docker run -d \
--name=lychee \
--memory="300m" \
-v /opt/docker/lychee/conf:/conf \
-v /opt/docker/lychee/uploads:/uploads \
-v /opt/docker/lychee/sym:/sym \
-e PUID=1000 \
-e PGID=1000 \
-e PHP_TZ=America/New_York \
-e TIMEZONE=America/New_York \
-e DB_CONNECTION=mysql \
-e DB_HOST=35.164.210.202 \
-e DB_PORT=3306 \
-e DB_DATABASE=lychee \
-e DB_USERNAME=iooio \
-e DB_PASSWORD=5320di \
-e APP_URL=http://192.168.5.229:90 \
-e APP_FORCE_HTTPS=false \
-e TRUSTED_PROXIES=* \
-p 90:80 \
lycheeorg/lychee执行
docker ps:root@proxmoxubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ef1b2448d3ac lycheeorg/lychee "/entrypoint.sh nginx" 51 seconds ago Up 49 seconds (healthy) 0.0.0.0:90->80/tcp, [::]:90->80/tcp lychee
root@proxmoxubuntu:~#
然后常出现了一个扯淡的现象:lychee仅能加载远程mysql中的模糊缩略图
ChatGPT 说:
其实这里涉及几个关键点,需要理清:
MySQL 数据库里并不直接存储图片文件
- MySQL 里存的是图片的元数据和文件路径(比如文件名、路径、缩略图路径等)。
- 图片本身是存放在 Lychee 服务器的文件系统里的,数据库只存文件位置或索引。
Lychee 访问图片是通过 Web 服务器直接读取本地磁盘文件
- 当浏览器访问图片时,请求会发送到运行 Lychee 的服务器(即 Web 服务器)。
- 服务器根据数据库中图片路径,直接去本地文件系统读取对应图片文件,再返回给浏览器。
- 数据库只是告诉 Lychee 图片存在“哪儿”,而不是把图片内容从数据库传出来。
为什么“远程 MySQL”依然能正常显示图片?
- 远程 MySQL 只是一个数据库服务,它保存路径和索引,Lychee 服务器连接它取数据。
- 关键是图片文件必须在 Lychee 服务器上(Web 服务器上)存在。
- 只要 Lychee 服务器能通过网络连接远程 MySQL,查询到图片路径,且图片文件在本地目录,图片显示就正常。
缩略图为什么也能显示?
- 缩略图和原图一样,都是存成文件,路径存数据库。
- Lychee 根据数据库里的缩略图路径,访问本地文件系统对应文件。
- 远程数据库不影响文件的实际读取。
如果图片文件和数据库不在同一服务器,图片无法显示的原因
- 如果 Lychee 服务器本地没有对应图片文件(不管数据库是本地还是远程),请求图片时会 404。
- 数据库远程,只要网络连通和权限正常,查询路径没问题,能拿到文件路径;
但文件系统没图片,访问就失败。
简单总结:
| 作用 | 位置 | 说明 |
|---|---|---|
| MySQL 数据库 | 远程服务器 | 存储图片路径、文件名、元数据 |
| 图片文件 | Lychee 服务器本地磁盘 | 真实图片和缩略图存放位置 |
| 浏览器访问图片 | Lychee 服务器(Web 服务器) | 根据数据库路径读取本地文件,返回给客户端 |
如果你希望图片和数据库分开,必须保证:
- 图片文件实际存储在 Lychee 服务器可访问的本地目录,且路径对应数据库路径。
- 或者通过网络文件系统(NFS/SMB等)把远程图片目录挂载到 Lychee 服务器。
lychee图床需要和数据库部署在一起
否则加载非常慢!!
现在本地安装数据库试试:
# 更新系统包 |
root 用户下安装nvm时的小坑
追加 nvm 初始化代码到
/root/.bashrc执行下面命令:
echo 'export NVM_DIR="$HOME/.nvm"' >> /root/.bashrc
echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> /root/.bashrc重新加载 bashrc
source /root/.bashrc
测试 nvm 是否可用
nvm --version
如果输出版本号,说明成功了。
这是因为 nvm 的安装脚本本应该自动把初始化代码写入你的 shell 配置文件(比如
.bashrc或.zshrc),但在某些情况下:- 安装脚本检测不到你的 shell 类型,没自动写入;
- 你用的是 root 用户,脚本权限或者环境变量导致没写入;
- 之前的配置文件被覆盖或者没有权限修改。
所以你需要手动把加载 nvm 的代码加到
.bashrc,才能让 shell 识别nvm命令。
简单说就是:
安装时它默认只修改了当前普通用户的配置文件,或者没成功写入 root 用户的配置文件,所以你得自己手动加进去让 root 用户生效。
紧急将proxmox网卡直通给openwrt
设置网卡直通
安装nvm包管理工具时,遇到了需要挂梯子才可以正常拉取的情况,为了避免以后同样的麻烦,先解决一下。
- 编辑 grub 配置文件:
nano /etc/default/grub |
找到这一行:
GRUB_CMDLINE_LINUX_DEFAULT="quiet" |
修改为:
- 如果你是 Intel CPU:
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on" |
- 如果你是 AMD CPU:
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on" |
💡 你可以用 lscpu | grep Vendor 来确认 CPU 类型。
- 更新 grub:
update-grub |
- 加载 vfio 模块(可选但建议):
echo -e "vfio\nvfio_iommu_type1\nvfio_pci\nvfio_virqfd" >> /etc/modules |
然后立即加载(无需重启):
modprobe vfio |
- 重启系统:
update-initramfs -u -k all |
- 验证是否启用成功:
重启后运行:
dmesg | grep -e DMAR -e IOMMU |
如果你看到:
mathematica复制编辑DMAR: IOMMU enabled |
✅ 就说明启用了。
接下来要安装 op
创建虚拟机,暂不添加启动介质,磁盘删掉,cpu类别选择host..
然后,宿主中执行:
qm importdisk 100 /var/lib/vz/template/iso/Openwrt.img local-lvm |
✅ 把 Openwrt.img 这个磁盘镜像文件,导入到 ID 为 100 的虚拟机中,作为一个虚拟硬盘,存储在 Proxmox 的 local-lvm 存储池中。
接下来,双击这款磁盘镜像,确认添加,然后调整引导顺序,既可以启动op安装!
op 做主路由还是二级路由或旁路由?
先说一下第一次折腾完毕的方案吧:
首先,华硕路由器作为主路由器pppoe拨号,lan口(192.168.5.1)怼在op(op虚拟在pve当中)的wan网口(dhcp客户端),然后剩余的一个lan口(此两个网口均物理直通)ip地址为192.168.10.1,没错,这种玩法,就是让op做了二级路由,并且桥接了一个虚拟接口,该虚拟接口分配给了位于pve中的ubuntu。
这样的弊端,家里需要开启两台无线路由器。
所以接下来很可能会换方法,直接让op做主路由,尽管他是装置pve内的虚拟机,只需要更改op wan口的协议为 pppoe ,设置拨号即可。然后,将之前的主路由器模式改为无线中继,直接转发op的lan口,lan 口的ip地址仍继续使用192.168.10.1就行..
记得设置好启动顺序 ~
2025-10-16 - 之前的 vmbr_0 完全无必要在op中挂载!
前置梳理
在 Proxmox VE 初始化安装完成后,系统会自动创建一个 Linux Bridge(虚拟网桥),通常命名为:
vmbr0 |
并且需要把一个物理网卡桥接到 vmbr0 上,我选择的是编号为enp1s0的那个。
📊 默认拓扑(示意)
[外部网络 / 路由器] |
🔧 二、默认设置的作用
| 功能 | 说明 |
|---|---|
vmbr0 | 相当于虚拟交换机,把物理网卡和虚拟机连在一起 |
enp1s0 | 实际物理接口,用来连到外部路由器或交换机 |
| PVE 主机 IP | 通常配置在 vmbr0 上,而不是直接在物理接口上 |
三、你提到的这点非常关键:
“该物理接口可用于物理线连接访问 PVE 的保险,对吧?”
✅ 是的,没错。
解释如下:
- 因为
vmbr0是桥接在物理接口(如enp1s0)上的; - 所以当你用网线把这块网卡连到路由器或电脑上时,
- 外部设备可以通过同一网段访问
PVE 管理界面(https://<vmbr0-IP>:8006); - 同时虚拟机也可以通过这条桥接链路访问外网或内网;
- 外部设备可以通过同一网段访问
- 即使虚拟机配置错误、虚拟交换机乱了,只要物理线连着这块网卡,
PVE依然能通过它访问到(除非你把桥彻底删掉)。
四、总结一句话:
vmbr0 就是你 PVE 的“保险”访问通道。
它桥接了物理网口(通常是 eno1/eth0),你插上网线、在同一网段,就能访问 PVE 的 Web 界面、SSH、以及所有桥接网络的虚拟机。
最佳实践:
| 场景 | 建议 |
|---|---|
| 家用 / 单网口主机 | 保留 vmbr0 桥接默认设置 |
| 有多网口的服务器 | 一张网卡专门用于 PVE 管理(vmbr0),另一张用于虚拟机或 OpenWrt 的 WAN/LAN |
| 为安全起见 | 可给 vmbr0 单独分配一个管理网段,避免与虚拟机网络混用 |
🧩当前架构
- OpenWrt 虚拟机 (OP VM)
- 有两块网卡(均为物理直通)
- WAN → 直通网口1(外网)
- LAN → 直通网口2(内网)
- LAN 地址:
192.168.10.1 - DHCP:开启(负责分配 192.168.10.x 网段 IP)
- 有两块网卡(均为物理直通)
- PVE 主机
- 创建了一个虚拟网桥
vmbr_op - 并将 OpenWrt LAN 所直通的物理口 也桥接给了
vmbr_op vmbr_op自身分配了一个 IP:192.168.10.99
- 创建了一个虚拟网桥
- Ubuntu 虚拟机
- 网卡接入
vmbr_op - IP 为:
192.168.10.224
- 网卡接入
✅ 逻辑理解
“vmbr_op 可以为不同虚拟设备分配不同 IP 吗?”
✔️ 答案是:可以的,而且这正是 Linux 网桥(bridge)的工作原理。
vmbr_op 并不是一张「拥有独立 IP 的网卡」,而是一个 虚拟交换机(Virtual Switch)。
它的功能是让所有连接到它的设备(OpenWrt、Ubuntu、PVE 自己)处于同一局域网中。
结论:之前的 vmbr_0 完全无必要在op中挂载!
让 pve op 做主路由的前置准备
执行nano /etc/network/interfaces,得到默认的网络设置如下:
auto lo
iface lo inet loopback
auto enp1s0
iface enp1s0 inet manual
iface enp2s0 inet manual
iface enp3s0 inet manual
iface ens9 inet manual
iface enp5s0 inet manual
iface enp6s0 inet manual
auto vmbr0
iface vmbr0 inet static
address 192.168.5.99/24
gateway 192.168.5.1
bridge-ports enp1s0
bridge-stp off
bridge-fd 0
auto vmbr_op
iface vmbr_op inet manual
bridge-ports none
bridge-stp off
bridge-fd 0
source /etc/network/interfaces.d/*✅ 当前配置解读
auto lo
iface lo inet loopback- 本地回环设备,默认,正常。
auto enp1s0
iface enp1s0 inet manualenp1s0是你当前连接主路由的物理 LAN 网口,用于外网访问。- 它被
vmbr0桥接使用。
auto vmbr0
iface vmbr0 inet static
address 192.168.5.99/24
gateway 192.168.5.1
bridge-ports enp1s0
bridge-stp off
bridge-fd 0vmbr0是你当前的主网桥,桥接了物理网口 enp1s0。- 分配了 IP
192.168.5.99,这是你当前访问 PVE 的地址。 - 所有虚拟机使用
vmbr0就可以访问外网。
auto vmbr_op
iface vmbr_op inet manual
bridge-ports none
bridge-stp off
bridge-fd 0vmbr_op是你为 OpenWrt LAN 创建的纯虚拟桥。- 目前还没分配 IP(手动模式),所以 PVE 本机无法通过此网桥通信。
✅ 下一步操作:让 PVE 本机加入
vmbr_op你只需把
vmbr_op的配置从inet manual改为inet static,并添加 IP 信息:auto vmbr_op
-iface vmbr_op inet manual
+iface vmbr_op inet static
+ address 192.168.10.99
+ netmask 255.255.255.0
+ gateway 192.168.10.1
bridge-ports none
bridge-stp off
bridge-fd 0⚠️ 注意:如果你同时保留了 vmbr0 的默认网关
192.168.5.1,那就不要在vmbr_op再写 gateway,否则可能冲突。✅ 推荐方案:设置
vmbr_op无 gateway如果你当前的
vmbr0(192.168.5.99)是 PVE 的管理口,并且未来也继续保留它用于访问 PVE,那vmbr_op不要再设网关。也就是说:
auto vmbr_op
iface vmbr_op inet static
address 192.168.10.99
netmask 255.255.255.0
bridge-ports none
bridge-stp off
bridge-fd 0✅ 这样配置后,PVE 会在 192.168.10.99 网段“上线”,但不走这条路由出外网。
✅ 修改后操作:
- 保存文件后,运行:
ifreload -a
或重启网络服务:
systemctl restart networking
也可以选择重启 PVE(保险做法):
reboot
填坑记录1:op版本还是老的香,新版有意想不到的bug,例如:esir新版的高大全,无法使用列表模式,非常的操蛋,我选择装回之前的2021版;
填坑记录2:pve安装op,概览当中显示的网口顺序和命名,实际为pve宿主机中为op添加的网口顺序,从eth0开始,依此命名,最佳实践为,启动之前添加好所有网口,虚拟在前,物理直通在后,安装完毕,(好像是)默认为第一个eth0 lan 口写入管理地址:192.168.5.1。
其中,需要注意的是 vbmr_0 无需在op虚拟机中添加:
如果你现在让 OP 也连接
vmbr0,就会变成:- WAN、LAN、vmbr0 三个网络同时挂在同一台虚拟机上,
- 这容易造成 路由混乱、ARP 冲突,甚至可能让 OP 把 PVE 自己“踢下线”。
从控制台进入系统后,尽量先不要着急改ip,正确的做法是先进入ui界面勾选lan口,然后更改lan口ip为另一网段,例如:192.168.10.1。
至此,基本上小工告成。
为什么?
op做二级路由时,为什么 Windows(192.168.10.x)能访问 PVE(192.168.5.99)?
情况 1:OpenWRT 的 WAN 口连接到主路由(NAT 模式)
- OpenWRT 的 WAN 口从主路由获取 IP(如
192.168.5.x),而 LAN 口是192.168.10.1。 - Windows 连接 OpenWRT 的 WiFi,获取
192.168.10.x的 IP。 - 默认情况下,OpenWRT 会启用 NAT(网络地址转换),使得 LAN 设备(Windows)可以通过 WAN 口访问外网(包括主路由和 PVE)。
- NAT 的作用:Windows 的流量会被 OpenWRT 转换为 WAN 口的 IP(
192.168.5.x)访问主路由,主路由认为流量来自 OpenWRT,而不是 Windows。 - 因此,Windows 可以访问 PVE,因为 OpenWRT 做了 NAT 转发。
✅ 这是最常见的情况,也是当前能访问 PVE 的原因。
lychee
初始化数据库
root用户执行
sudo mysql_secure_installation,进行数据库初始化:| 步骤 | 作用 | 推荐操作(生产环境) |
| ————————— | ———————————- | ———————————- |
| 启用密码验证组件 | 防止设置弱密码 | 是 |
| root 认证方式 | 默认为 auth_socket 插件 | 本地保留 / 远程改为密码 |
| 删除匿名用户 | 防止无授权访问 | 是 |
| 禁止 root 远程登录 | 降低被暴力破解风险 | 是 |
| 删除 test 数据库 | 减少潜在安全风险 | 是 |
| 重新加载权限表 | 使配置生效 | 是 |接下来,创建数据库表,以及lychee的专属用户:
CREATE DATABASE lychee CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'lychee'@'%' IDENTIFIED BY '386898136Di!';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON lychee.* TO 'lychee'@'%';
FLUSH PRIVILEGES;以下情况,表示 MySQL 只接受本地连接,远程连接会被拒绝。
sudo grep -r "bind-address" /etc/mysql/
/etc/mysql/mysql.conf.d/mysqld.cnf:bind-address = 127.0.0.1得到:
root@proxmoxubuntu:~# sudo grep -r "bind-address" /etc/mysql/
/etc/mysql/mysql.conf.d/mysqld.cnf:bind-address = 127.0.0.1
/etc/mysql/mysql.conf.d/mysqld.cnf:bind-address = 127.0.0.1
/etc/mysql/mysql.conf.d/mysqld.cnf:mysqlx-bind-address = 127.0.0.1你需要用编辑器打开文件,比如:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
找到
bind-address行,将其改为:bind-address = 0.0.0.0
保存并重启 MySQL 服务:;
sudo systemctl restart mysql
使用 Docker Compose 管理(推荐)
将配置写到 docker-compose.yml,修改时只需修改文件然后重新 docker-compose up -d,更方便管理。
使用 docker-compose
安装 Docker Compose CLI 插件,下载最新 Compose CLI 插件:
mkdir -p ~/.docker/cli-plugins/ |
然后试试:
docker compose version |
✅ 第一步:创建文件夹(如果还没有)
mkdir -p /opt/docker/lychee |
✅ 第二步:创建 docker-compose.yml 文件
你可以使用你熟悉的文本编辑器,比如 nano:
nano /opt/docker/lychee/docker-compose.yml |
用 cat > 文件名 快速粘贴(推荐)
cat > /opt/docker/lychee/docker-compose.yml |
粘贴以下 纯文本内容 后,按下 Ctrl + D 结束输入保存。
version: "3.8" |
按下 Ctrl + O 保存,回车确认,然后 Ctrl + X 退出编辑器。
✅ 第三步:使用 Compose 启动容器(注意第一步,需要先进到目录中去)
cd /opt/docker/lychee |
✅ 后续常用命令
| 命令 | 说明 |
|---|---|
docker compose up -d | 后台启动容器 |
docker compose down | 停止并删除容器 |
docker compose logs -f | 查看实时日志 |
docker compose ps | 查看当前运行状态 |
再进阶 - 使用.env存储易发生变动的变量
nano /opt/docker/lychee/.env |
用 cat > 文件名 快速粘贴(推荐)
cat > /opt/docker/lychee/.env |
粘贴以下 纯文本内容 后,按下 Ctrl + D 结束输入保存。
PUID=1000 |
- 如果只是简单修改配置文件并想更新容器,可以用:
docker compose up -d --force-recreate |
docker compose up -d --force-recreate 也是让修改后的 .env 文件配置生效的好办法。
它会:
- 停止并删除旧容器
- 重新基于最新配置(包括
.env)创建并启动容器 - 保留你的挂载卷数据不丢失
这个命令其实比单纯重启更“彻底”,适合确保配置完全更新的场景。
总结:
| 命令 | 作用 | 适用情况 |
|---|---|---|
docker compose restart lychee | 只重启容器,不重新创建,配置不变 | 仅容器重启,无配置修改时 |
docker compose up -d --force-recreate | 强制重建容器,应用最新配置 | 修改环境变量或配置文件时 |
所以,修改 .env 后,直接执行:
docker compose up -d --force-recreate |
是个非常好的选择。
nginx反向代理
点击查看详情
📌 1. 确保 Nginx 已安装
如果你还没有安装 Nginx,可以执行:
sudo apt update |
然后启动并设置开机自启:
sudo systemctl start nginx |
📌 2. 创建一个新的 Nginx 配置文件
你可以在 /etc/nginx/sites-available/ 下创建一个新的配置文件,比如 lychee.conf:
sudo nano /etc/nginx/sites-available/lychee.conf |
使用命令:
sudo tee /etc/nginx/sites-available/lychee.conf <<-'EOF' |
是一个 Here Document(heredoc) 的写法,用于 将多行文本内容直接写入文件,同时避免手动粘贴时可能出现的格式问题(如换行丢失)。下面详细解释它的作用和用法:
配置文件内容(HTTP 版本,稍后配置 HTTPS)
server { |
粘贴后,回车切换下一行,顶格输入EOF,再按回车退出。
📌 3. 启用新的 Nginx 配置
创建软链接
sudo ln -s /etc/nginx/sites-available/lychee.conf /etc/nginx/sites-enabled/ |
这条命令的作用是创建一个符号链接(软链接),用于启用 Nginx 的站点配置。
测试 Nginx 配置
sudo nginx -t |
如果没有错误,重启 Nginx:
sudo systemctl restart nginx |
关于 server_name
- 当用户在浏览器中输入域名(如
yourdomain.com),过程是这样的:- DNS 查询:浏览器先通过 DNS 将
yourdomain.com解析为一个 IP 地址,比如123.123.123.123。 - 浏览器发送请求:它向该 IP 地址的服务器发送一个请求,同时在 HTTP 请求头中带上了
Host: yourdomain.com。 - Nginx 接收请求:Nginx 收到这个请求后,会根据
server_name来判断是哪个虚拟主机要响应这个请求。
- DNS 查询:浏览器先通过 DNS 将
为什么创建这种软连接?
✅ 工作机制解释:
主配置文件:
/etc/nginx/nginx.conf是主配置文件,其中有一行:include /etc/nginx/sites-enabled/*;
这表示 Nginx 启动时会自动加载
sites-enabled目录下的所有配置文件。两个相关目录:
/etc/nginx/sites-available/:放置你写好的 Nginx 配置文件,可以有多个,但不会被自动加载。/etc/nginx/sites-enabled/:放置 Nginx 实际要启用的配置,一般通过软链接指向sites-available中的文件。
启用站点的正确方式:
假设你创建了一个配置文件:
sudo nano /etc/nginx/sites-available/my_site.conf
启用它(创建软链接):
sudo ln -s /etc/nginx/sites-available/my_site.conf /etc/nginx/sites-enabled/
重启或重载生效:
sudo nginx -t # 检查语法
sudo systemctl reload nginx
🔥 为什么这样设计?
这样做的好处是:
- 你可以随时修改、启用或禁用某个站点。
- 管理多个站点配置时更清晰、安全(避免直接修改
nginx.conf)。 - 保留
sites-available作为备份或草稿,启用再软链即可。
🧠 小提醒
- 配置文件名可以是任意的,如
myapp.conf、default等。 - 文件内容必须合法,否则
nginx -t会报错,导致 Nginx 无法重载。
如果你在 Docker 容器中使用的是 官方 Nginx 镜像,那默认是没有 sites-enabled/ 和 sites-available/ 这套结构的,而是直接用 /etc/nginx/nginx.conf 或 /etc/nginx/conf.d/*.conf。
所以如果你在容器里部署 Nginx,记得区分这两种结构。
lychee图床赞不支持其他端口部署
Lychee 图床目前在 APP_URL 中 确实不完全支持带端口号的配置,尤其是配合反向代理(Nginx)时,会导致以下典型问题:
❌ 现象回顾:
当 APP_URL=http://lychee.iooio.cn:9527 时,访问出现以下错误:
If you can read me, it means that you misconfigured Lychee. |
或控制台报错:
Refused to load the stylesheet... violates Content Security Policy... |
这些都说明 Lychee 识别到的 URL、路径、协议或端口与它预期中的不一致。
🎯 原因分析
Lychee 是一个基于 Laravel 框架的 PHP 应用,它在内部使用 APP_URL:
- 生成资源链接(如 JS、CSS、图片)
- 校验请求来源是否可信
- 配合 CSP(Content Security Policy)进行前端安全策略检查
当你配置 APP_URL=http://lychee.iooio.cn:9527:
Laravel 认为这是标准 URL,会用来构造资源路径,如:
http://lychee.iooio.cn:9527/build/assets/app-xxxx.css
但是浏览器通过域名访问
lychee.iooio.cn(默认 80)时,不加端口号资源链接中的端口和页面本身不一致 → 触发 CSP 拒绝加载
✅ 正确做法(最佳实践)
✅ 方案 A(推荐)
使用 默认端口,让 APP_URL 不带端口号:
APP_URL=http://lychee.iooio.cn |
然后:
- 使用路由器/云防火墙将外部端口(如 9527)映射到内部主机的 80 端口
- 保持 Nginx 的监听端口为
listen 80;,并通过server_name控制转发
✅ 方案 B(启用 HTTPS)
- 配置
APP_URL=https://lychee.iooio.cn - 设置反向代理监听
443(开启 HTTPS) APP_FORCE_HTTPS=true强制走 HTTPS- 使用 Let’s Encrypt 免费证书自动续期(如配合
certbot)
🚫 不推荐的方案
- 在
APP_URL中加上端口号(Laravel/Lychee 对此支持不完整) - 在本地监听多个端口(如 Nginx
listen 9527;) → 会出现跳转和 CSP 错误
🧩 总结
| 选项 | 是否推荐 | 原因 |
|---|---|---|
APP_URL 带端口号 | ❌ 不推荐 | 造成资源路径错乱、CSP 报错 |
| 路由器将外部端口映射到主机 80 | ✅ 推荐 | 对外暴露非 80 端口,内部统一反代 |
APP_URL 不带端口 + server_name 控制 | ✅ 推荐 | 最兼容 Laravel 的反向代理方式 |
配置证书
安装 Let’s Encrypt 的 Certbot 工具
sudo apt update |
🚀 使用 Certbot 自动为 Nginx 配置 HTTPS
执行以下命令:
sudo certbot --nginx |
然后根据提示:
- 输入你的邮箱地址
- 同意服务条款
- 选择你要启用 HTTPS 的域名(如
lychee.iooio.cn) - Certbot 会自动配置好 Nginx 的 SSL 段落
最后一步会提示选择之前使用nginx配置好的http反代域名,选择相应的数字,确认即可自动申请下来证书:
🔐 成功后 Nginx 配置(自动生成如下)
server { |
🌐 更新 .env 文件(Lychee)
APP_URL=https://lychee.iooio.cn |
但:
在 运营商封闭了443端口 的前提下,配置 HTTPS 证书对于公网访问是没有意义的,原因如下:
🚫 为什么没有意义?
- HTTPS 的标准端口是 443,浏览器访问
https://yourdomain.com默认就是请求 443。 - 如果运营商封禁了 443,那么:
- 证书可以生成 ✅
- 本地访问可以正常 ✅
- 但公网用户无法访问 ❌
- 虽然可以尝试使用 端口转发(例如把外网 8443 转发到内网 443),但:
- 用户就需要手动输入
https://yourdomain.com:8443,这样就 破坏了 Lychee 的 APP_URL 识别机制。 - 证书也无法通过 Let’s Encrypt 自动验证,因为默认验证是走端口 80 或 443。
- Lychee 很严格地校验
APP_URL,加端口号会导致前端资源无法加载,你已经遇到过这种情况。
- 用户就需要手动输入
✅ 有意义的场景(可选):
- 如果你是局域网内访问、使用 自签名证书 或配置了 自建 DNS + 可信中间代理,还是可以用 HTTPS。
- 或者你有能力切换到没有封锁 443 的服务器,比如:
- 买个便宜的云服务器(阿里云、腾讯云、Oracle Free Tier)
- 让别人帮你做外部反代
💡 替代方案建议
由于 Lychee 不支持端口号加在 APP_URL 后,所以:
- ✅ 推荐你用 80 端口 + HTTP 反向代理 + 防火墙控制访问来源
- ✅ 或者部署一个中间转发层(例如 Caddy 或 Nginx 的公网反代服务器)
- ❌ 不推荐将 HTTPS 部署在非标准端口(如 8443、9443),这会引起兼容性和 Lychee 报错
🔚 结论
在运营商封闭 443 的环境下,不建议折腾 HTTPS,除非你满足以下条件之一:
- 有公网服务器做中继(外部反向代理)
- 不使用 Lychee 默认的 URL 检查机制(自行魔改)
- 可以通过 DNS-01 方式手动生成证书(但仍无法解决 443 封锁问题)
否则,建议继续使用 HTTP + 强口令 + 安全网络策略,作为过渡方案。
lychee Nginx 专属坑位
实际情况:
- Lychee 服务本身可以在任何端口运行(80, 90, 443, 8443 等)
- APP_URL 的端口限制只影响 Lychee 生成的内部 URL 和重定向
- 反向代理可以解决这个问题
解决方案架构
用户访问: https://lychee.iooio.cn:8443 |
Nginx 配置关键点:
server { |
为什么这样能工作?
- 用户看到的是:
https://lychee.iooio.cn:8443 - Lychee 看到的是:通过 HTTP 头知道真实访问地址
- Lychee 生成的链接:基于
APP_URL+ 头部信息
点击查看详情
经过再次确认,nginx 完全可以对lychee服务进行反向代理:
修改配置
nano /etc/nginx/sites-available/lychee.conf 或直接: |
这两行新增的代理头是为了让后端应用(Lychee)知道客户端原始访问的地址信息。 含义:告诉 Lychee 用户实际访问的域名 示例: 作用:Lychee 可以根据这个头来生成正确的资源链接地址。 含义:告诉 Lychee 用户实际访问的端口 示例: 作用:Lychee 生成资源链接时会包含正确的端口号。 为什么需要这些头? 没有这些头时: 有这些头时: 改进建议 当前配置的硬编码问题: 应该改为: 这样如果你修改监听端口,配置会自动适应。 总结 这两个头的作用就是保持访问地址的一致性,确保 Lychee 生成的资源链接与用户实际访问地址匹配,避免资源加载失败。 新增部分的含义
proxy_set_header X-Forwarded-Host $host;http://lychee.iooio.cn:9528X-Forwarded-Host: lychee.iooio.cnlychee.iooio.cn 访问的proxy_set_header X-Forwarded-Port 9528;http://lychee.iooio.cn:9528X-Forwarded-Port: 95289528 端口访问的用户访问: lychee.iooio.cn:9528
↓
Nginx 转发到: localhost:90
↓
Lychee 只看到: localhost:90
↓
Lychee 生成错误链接: http://localhost:90/resources/image.jpg用户访问: lychee.iooio.cn:9528
↓
Nginx 转发并添加头:
X-Forwarded-Host: lychee.iooio.cn
X-Forwarded-Port: 9528
↓
Lychee 看到原始访问信息
↓
Lychee 生成正确链接: http://lychee.iooio.cn:9528/resources/image.jpgproxy_set_header X-Forwarded-Port 9528; # ❌ 硬编码
proxy_set_header X-Forwarded-Port $server_port; # ✅ 动态获取
然后,修改 lychee 环境变量中的 app_url:
nano /opt/docker/lychee/.env |
然后,cd 到 docker-compose.yml 所在的文件夹:
cd /opt/docker/lychee |
至此,应该nginx可以正常转发请求到 lychee 了!
配置 https 证书
证书配置:
点击查看详情
sudo certbot certonly --manual --preferred-challenges dns -d lychee.iooio.cn |
接下来,登录域名服务商(如阿里云、腾讯云、Cloudflare等)的DNS管理面板,添加以下记录:
| 记录1 | 值 |
|---|---|
| 记录类型 | CAA |
| 主机记录 | lychee |
| 记录值 | 0 issue "letsencrypt.org" - 带着双引号 |
| TTL | 10分钟 |
以及:
- 记录类型:
TXT - 主机名:
_acme-challenge.lychee.iooio.cn- 不要忘了.lychee - 记录值:
填生成的记录值 - TTL: 默认值(通常600秒或自动)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
根据以上结果,修改 nginx 配置:
server { |
最后,需要修改 lychee 的 .env 文件中的 app_url,确保静态资源可以正确拼接:
APP_URL=https://lychee.iooio.cn:9528 # 改为https |
这样,理论上就应该通了。
自动续期
点击查看详情
关于ssh登录权限
点击查看详情
为root用户配置密码登录
sudo -i 切换至 root 用户,然后执行 sudo passwd root 为 root 用户设置密码
// 编辑配置文件 |
关键说明:
PermitRootLogin yes:允许 root 登录(如果之前是prohibit-password或no,需改为yes)。PasswordAuthentication yes:启用密码认证。PubkeyAuthentication no:禁用公钥认证(确保 root 只能密码登录)
某些系统(如 Ubuntu)会从 /etc/ssh/sshd_config.d/ 加载额外配置,检查是否有冲突:
sudo grep -r "PermitRootLogin\|PasswordAuthentication\|PubkeyAuthentication" /etc/ssh/sshd_config.d/ |
如果发现 PermitRootLogin no 或 PubkeyAuthentication yes 的配置,需删除或修改对应文件。
sudo nano /etc/ssh/sshd_config.d/50-cloud-init.conf |
最后,重启ssh服务:
// Debian/Ubuntu/Proxmox VE 等系统默认使用 ssh 作为服务名称 |
允许root密码登录,需要在生产环境中关闭。
为root复制一份公钥
公钥已经存储到了ubuntu用户中,在安装ubuntu系统时,我填写了github 账户,已经将公钥添加到了 ubuntu 用户中,只需以下几步即可:
1. 切换到 root 用户:
sudo -i |
2. 创建 root 的 .ssh 目录(如不存在):
mkdir -p /root/.ssh |
3. 将 ubuntu 用户的公钥复制到 root:
cat /home/ubuntu/.ssh/authorized_keys >> /root/.ssh/authorized_keys |
这会把
ubuntu的密钥授权也加到 root 里,两个用户可以使用同一个私钥登录服务器。
✅ 确保 SSH 配置允许 root 密钥登录
编辑 SSH 配置文件:
sudo nano /etc/ssh/sshd_config |
确保这几行配置是以下内容:
PermitRootLogin prohibit-password |
如果你写成
PermitRootLogin yes也可以,但更推荐prohibit-password,这样即使有人知道 root 密码,也不能用它登录。
保存并退出,然后:
sudo systemctl restart ssh |
配置 vitepress
点击查看详情
📌 1. 确保 Nginx 已安装
如果你还没有安装 Nginx,可以执行:
sudo apt update |
然后启动并设置开机自启:
sudo systemctl start nginx |
📌 2. 创建一个新的 Nginx 配置文件
你可以在 /etc/nginx/sites-available/ 下创建一个新的配置文件,比如 lychee.conf:
sudo nano /etc/nginx/sites-available/vitepress.conf |
使用命令:
sudo tee /etc/nginx/sites-available/vitepress.conf <<-'EOF' |
是一个 Here Document(heredoc) 的写法,用于 将多行文本内容直接写入文件,同时避免手动粘贴时可能出现的格式问题(如换行丢失)。下面详细解释它的作用和用法:
配置文件内容(HTTP 版本,稍后配置 HTTPS)
server { |
粘贴后,回车切换下一行,顶格输入EOF,再按回车退出。
关于 location / 的说明
VitePress 的 base 配置必须与你在 Nginx 中设置的访问路径保持一致,这是确保静态资源(JS、CSS、图片等)加载正常的关键。否则会出现样式丢失、页面空白、资源 404 等问题。
✅ 举个例子:
- 如果你想通过这个地址访问:
http://vitepress.iooio.cn:9528/ |
那你的配置应该是:
Nginx:
location / { |
VitePress .vitepress/config.ts:
export default { |
然后重新构建:
vitepress build |
- 如果你使用子路径访问,例如:
http://vitepress.iooio.cn:9528/vitepress_init/ |
那配置应为:
Nginx:
location /vitepress_init/ { |
VitePress .vitepress/config.ts:
export default { |
🔁 总结:
| 访问地址 | Nginx location | VitePress base |
|---|---|---|
http://域名:端口/ | / | '/' |
http://域名:端口/某路径/ | /某路径/ | '/某路径/' |
👉 两者必须严格一致。
需要我帮你自动判断当前的路径和 base 是否一致,也可以贴上你的 config.ts 和实际访问路径,我来帮你检查。
📌 3. 启用新的 Nginx 配置
创建软链接
sudo ln -s /etc/nginx/sites-available/vitepress.conf /etc/nginx/sites-enabled/ |
这条命令的作用是创建一个符号链接(软链接),用于启用 Nginx 的站点配置。
测试 Nginx 配置
sudo nginx -t |
如果没有错误,重启 Nginx:
sudo systemctl restart nginx |
关于 server_name
- 当用户在浏览器中输入域名(如
yourdomain.com),过程是这样的:- DNS 查询:浏览器先通过 DNS 将
yourdomain.com解析为一个 IP 地址,比如123.123.123.123。 - 浏览器发送请求:它向该 IP 地址的服务器发送一个请求,同时在 HTTP 请求头中带上了
Host: yourdomain.com。 - Nginx 接收请求:Nginx 收到这个请求后,会根据
server_name来判断是哪个虚拟主机要响应这个请求。
- DNS 查询:浏览器先通过 DNS 将