Oracle Cloud ARM 安装 Proxmox VE 9:面向 LXC 的完整实战教程
本文记录一次在 Oracle Cloud ARM 云服务器上安装 Proxmox VE 9,并把它作为 LXC 容器平台使用的完整过程。
重点不是 KVM 虚拟机,而是 ARM64 LXC:安装 PVE、配置 OCI 安全的 NAT 网络、下载 ARM64 容器模板、创建 Debian / Ubuntu / OpenWrt / Kali / Oracle Linux 容器,以及把容器服务通过宿主机公网高端口转发出去。
变量约定
下面所有公网 IP、密码、端口都使用占位符。照抄时请替换成你自己的值。
<PUBLIC_IP> 你的云服务器公网 IP,例如 203.0.113.10
<HOST_PRIVATE_IP> 云服务器在 OCI VCN 里的内网 IP,例如 10.0.0.30
<ROOT_PASSWORD> 宿主机 root 密码
<CT_ROOT_PASSWORD> 容器 root 密码
<HOST_PORT> 宿主机公网高端口,例如 21025
<CT_IP> 容器内网 IP,例如 10.10.10.104
<CT_SERVICE_PORT> 容器服务端口,例如 SSH 是 22,HTTP 是 80
本文示例网络:
宿主主网卡:enp0s3
宿主公网 IP:<PUBLIC_IP>
宿主 OCI 内网 IP:<HOST_PRIVATE_IP>
LXC bridge:vmbr0
LXC 网关:10.10.10.1
LXC 网段:10.10.10.0/24
NAT 出口网卡:enp0s3
适用场景
本文适合:
- Oracle Cloud Infrastructure,也就是 OCI
- ARM64 / AArch64 实例
- Debian GNU/Linux 13 trixie
- Proxmox VE 9.x
- 主要跑 LXC 容器
- 不要求 KVM 虚拟机
- 容器通过 NAT 出网
- 容器服务通过宿主机公网高端口转发访问
一次实际安装后的版本示例:
pve-manager/9.2.9
running kernel: 7.0.14-6-pve
先说结论
Oracle Cloud ARM 实例可以安装 Proxmox VE 9,但建议把它当成 LXC 容器管理平台,而不是完整虚拟化平台。
很多 OCI ARM 实例没有 /dev/kvm,这会影响 KVM 虚拟机。但 LXC 容器不依赖 KVM,所以可以正常使用。
推荐路线:
- 使用 Debian 13 trixie ARM64。
- 添加 Proxmox VE 9 trixie arm64 软件源。
- 安装 PVE 内核并重启。
- 安装
proxmox-ve。 - 禁用 enterprise 源。
- 配置独立 LXC NAT bridge:
vmbr0。 - 从 Linux Containers 镜像站下载 ARM64 CT 模板。
- 创建容器时使用静态内网 IP。
- 需要公网访问的服务,在宿主机上做 DNAT 和 FORWARD。
为什么不 DD 重装
很多教程会用第三方 DD 脚本直接刷 Proxmox 镜像。如果当前系统已经是 Debian 13 ARM64,就没必要这么做。
直接 apt 安装更稳:
- 不需要重刷系统盘。
- 不容易破坏 OCI 的 SSH 和网卡配置。
- 出问题时更容易排查。
- 更适合只跑 LXC 的用途。
注意:Proxmox VE 8 的 bookworm 源主要是 amd64;ARM64 应使用 Proxmox VE 9 的 trixie 源。
安装前检查
确认架构:
uname -m
期望看到:
aarch64
确认系统版本:
cat /etc/os-release
期望是 Debian 13 trixie。
检查 KVM:
ls -l /dev/kvm
如果提示不存在,不用慌。没有 /dev/kvm 只是不适合跑 KVM 虚拟机,LXC 仍然可以用。
修改 hostname
Proxmox 不建议 hostname 是 localhost。这里以 pve 为例:
echo pve > /etc/hostname
hostnamectl set-hostname pve
修改 /etc/hosts,把主机名指向 OCI 内网 IP:
<HOST_PRIVATE_IP> pve.local pve
例如:
10.0.0.30 pve.local pve
如果机器上有 cloud-init,建议防止重启后 hostname 被改回去:
if [ -f /etc/cloud/cloud.cfg ]; then
grep -q '^preserve_hostname:' /etc/cloud/cloud.cfg \
&& sed -i 's/^preserve_hostname:.*/preserve_hostname: true/' /etc/cloud/cloud.cfg \
|| echo 'preserve_hostname: true' >> /etc/cloud/cloud.cfg
fi
安装基础工具
apt update
apt install -y ca-certificates wget curl gnupg
添加 Proxmox VE 9 ARM64 软件源
创建 keyring 目录:
install -d -m 0755 /etc/apt/keyrings
下载 Proxmox trixie 源密钥:
wget -O /etc/apt/keyrings/proxmox-release-trixie.gpg \
https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg
添加 no-subscription 源:
cat > /etc/apt/sources.list.d/pve-install-repo.list <<'EOF'
deb [arch=arm64 signed-by=/etc/apt/keyrings/proxmox-release-trixie.gpg] http://download.proxmox.com/debian/pve trixie pve-no-subscription
EOF
更新软件源:
apt update
升级系统并安装 PVE 内核
apt full-upgrade -y
apt install -y proxmox-default-kernel
安装内核后重启:
systemctl reboot
重启回来后检查内核:
uname -r
正常会看到类似:
7.0.14-6-pve
安装 Proxmox VE 主体
为了避免 Postfix 弹交互窗口,可以先预置成本地投递:
echo 'postfix postfix/mailname string pve.local' | debconf-set-selections
echo 'postfix postfix/main_mailer_type select Local only' | debconf-set-selections
安装 PVE:
DEBIAN_FRONTEND=noninteractive apt install -y proxmox-ve postfix open-iscsi chrony
检查版本:
pveversion | head -n 1
检查失败服务:
systemctl --no-pager --state=failed
正常情况下应显示:
0 loaded units listed.
禁用 enterprise 源
安装 proxmox-ve 后,系统可能会自动生成 enterprise 源。没有订阅时,后续 apt update 可能报错。
如果存在:
/etc/apt/sources.list.d/pve-enterprise.sources
建议改成:
Enabled: no
Types: deb
URIs: https://enterprise.proxmox.com/debian/pve
Suites: trixie
Components: pve-enterprise
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
注意:deb822 格式不要只注释 Types:,否则 apt 会认为源文件 malformed。正确做法是加:
Enabled: no
然后验证:
apt update
apt -s upgrade
访问 PVE 面板
PVE Web 默认端口是 8006:
https://<PUBLIC_IP>:8006/
登录:
用户名:root
Realm:Linux PAM standard authentication
密码:宿主机 root 密码
如果打不开,检查 OCI 安全列表或网络安全组是否放行 TCP 8006。
OCI 上为什么不要直接桥接主网卡
OCI 的网络不适合把公网主网卡直接桥接给容器。原因包括:
- OCI VNIC 对 MAC/IP 绑定比较严格。
- 公网 IP 是绑定到云网卡上的,不是普通二层网络里随便漂。
- 直接桥接
enp0s3可能影响宿主机 SSH。 - 容器公网暴露应该由宿主机 NAT/转发处理。
更稳的方案是:
公网流量
↓
OCI VNIC / enp0s3
↓
PVE 宿主机 iptables DNAT
↓
vmbr0
↓
LXC 容器 10.10.10.x
容器出网路径:
LXC 容器 10.10.10.x
↓
网关 10.10.10.1,也就是 vmbr0
↓
宿主机 MASQUERADE
↓
enp0s3
↓
互联网
配置 LXC NAT 网络
本文使用:
宿主主网卡:enp0s3
LXC bridge:vmbr0
LXC 网段:10.10.10.0/24
LXC 网关:10.10.10.1
NAT 出口:enp0s3
为什么要用 dummy0
正常 PVE 空桥可以写 bridge-ports none,但某些 ifupdown2 版本对空 bridge 写法不友好,可能报错。
另外,有些 PVE 9 环境不会把 /etc/network/interfaces.d/ 里的 bridge 显示到创建 CT 的下拉框里。
稳定写法:
- 把
vmbr0写进/etc/network/interfaces主文件。 - 创建
dummy0虚拟网卡。 - 让
vmbr0桥接dummy0。 - 不要把 OCI 主网卡
enp0s3加进vmbr0。
最终 /etc/network/interfaces 示例
编辑 /etc/network/interfaces:
auto lo
iface lo inet loopback
auto enp0s3
iface enp0s3 inet dhcp
auto dummy0
iface dummy0 inet manual
pre-up ip link add dummy0 type dummy || true
post-down ip link delete dummy0 type dummy 2>/dev/null || true
auto vmbr0
iface vmbr0 inet static
address 10.10.10.1/24
bridge-ports dummy0
bridge-stp off
bridge-fd 0
post-up iptables -t nat -C POSTROUTING -s 10.10.10.0/24 -o enp0s3 -j MASQUERADE 2>/dev/null || iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o enp0s3 -j MASQUERADE
post-down iptables -t nat -D POSTROUTING -s 10.10.10.0/24 -o enp0s3 -j MASQUERADE 2>/dev/null || true
启用 IPv4 转发:
cat > /etc/sysctl.d/99-pve-lxc-nat.conf <<'EOF'
net.ipv4.ip_forward=1
EOF
sysctl --system
检查:
sysctl net.ipv4.ip_forward
iptables -t nat -S POSTROUTING | grep 10.10.10.0/24
期望看到:
net.ipv4.ip_forward = 1
-A POSTROUTING -s 10.10.10.0/24 -o enp0s3 -j MASQUERADE
远程云服务器上应用网络配置有断连风险。建议先检查语法:
ifreload -a -s
确认有控制台或救援方式后再实际应用。
如果只是让 PVE 面板刷新网络信息,可以重启 PVE API 和 Web:
systemctl restart pvedaemon pveproxy
检查 PVE 是否识别 vmbr0:
pvesh get /nodes/$(hostname)/network --type any_bridge
应能看到 vmbr0,类型是 bridge。
IPv6 / DHCPv6 注意事项
OCI 可能已经给宿主机分配了 IPv6 地址,但这不一定适合交给 ifupdown2 管理。
如果 /etc/network/interfaces 里写了:
iface enp0s3 inet6 auto
或类似 DHCPv6 配置,ifreload -a 可能会触发 dhclient -6,然后失败。
如果容器只需要 IPv4 NAT,建议宿主机 ifupdown2 配置里只保留:
auto enp0s3
iface enp0s3 inet dhcp
让 OCI 运行时自己处理宿主 IPv6,LXC 网络则走 IPv4 NAT。
ARM64 CT 模板从哪里找
PVE 自带模板列表里的 ARM64 模板很少。可以从 Linux Containers 镜像站下载:
https://images.linuxcontainers.org/images/
目录格式大致是:
https://images.linuxcontainers.org/images/<发行版>/<版本>/arm64/default/<日期>/rootfs.tar.xz
例如 Debian 13 trixie ARM64:
https://images.linuxcontainers.org/images/debian/trixie/arm64/default/
进入最新日期目录,下载 rootfs.tar.xz 到 PVE 模板目录:
cd /var/lib/vz/template/cache
wget -O debian-13-trixie-default_YYYYMMDD_arm64.tar.xz \
https://images.linuxcontainers.org/images/debian/trixie/arm64/default/YYYYMMDD_HH:MM/rootfs.tar.xz
如果目录里有 SHA256SUMS,建议校验:
wget -O SHA256SUMS \
https://images.linuxcontainers.org/images/debian/trixie/arm64/default/YYYYMMDD_HH:MM/SHA256SUMS
sha256sum debian-13-trixie-default_YYYYMMDD_arm64.tar.xz
把输出和 SHA256SUMS 里的 rootfs.tar.xz 对应值比较。
确认 PVE 能识别模板:
pveam list local
创建普通 Debian / Ubuntu 容器
假设创建一个 Debian 容器:
VMID:100
hostname:debian
IP:10.10.10.101/24
网关:10.10.10.1
DNS:1.1.1.1 8.8.8.8
CPU:1 核
内存:2048 MB
命令示例:
pct create 100 local:vztmpl/debian-13-trixie-default_YYYYMMDD_arm64.tar.xz \
--arch arm64 \
--ostype debian \
--hostname debian \
--cores 1 \
--memory 2048 \
--swap 512 \
--rootfs local:8 \
--net0 name=eth0,bridge=vmbr0,ip=10.10.10.101/24,gw=10.10.10.1 \
--nameserver '1.1.1.1 8.8.8.8' \
--searchdomain local \
--unprivileged 1 \
--features nesting=1 \
--onboot 1
启动:
pct start 100
设置 root 密码:
pct exec 100 -- passwd root
检查网络:
pct exec 100 -- ip addr show eth0
pct exec 100 -- ip route
pct exec 100 -- cat /etc/resolv.conf
pct exec 100 -- ping -c 3 1.1.1.1
pct exec 100 -- getent hosts deb.debian.org
创建 OpenWrt 容器
OpenWrt 比普通 Debian/Ubuntu 特殊。它默认把 eth0 当成 LAN,并且常见默认 IP 是 192.168.1.1,所以 PVE 的 net0 ip=... 不一定会自动生效。
创建示例:
pct create 102 local:vztmpl/openwrt-24.10.x-armsr-armv8-rootfs.tar.gz \
--arch arm64 \
--ostype unmanaged \
--hostname openwrt \
--cores 1 \
--memory 2048 \
--swap 512 \
--rootfs local:2 \
--net0 name=eth0,bridge=vmbr0,ip=10.10.10.103/24,gw=10.10.10.1 \
--nameserver '1.1.1.1 8.8.8.8' \
--searchdomain local \
--unprivileged 0 \
--features nesting=1 \
--onboot 1
启动:
pct start 102
进入容器后修改 OpenWrt 网络:
pct exec 102 -- sh -c 'cp /etc/config/network /etc/config/network.before-pve-nat'
pct exec 102 -- sh -c "cat > /etc/config/network <<'EOF'
config interface 'loopback'
option device 'lo'
option proto 'static'
option ipaddr '127.0.0.1'
option netmask '255.0.0.0'
config globals 'globals'
option ula_prefix 'fd00:10:10:10::/48'
config device
option name 'br-lan'
option type 'bridge'
list ports 'eth0'
config interface 'lan'
option device 'br-lan'
option proto 'static'
option ipaddr '10.10.10.103'
option netmask '255.255.255.0'
option gateway '10.10.10.1'
list dns '1.1.1.1'
list dns '8.8.8.8'
EOF
/etc/init.d/network restart"
设置 OpenWrt root 密码:
pct exec 102 -- passwd root
安装 LuCI 中文包示例:
pct exec 102 -- opkg update
pct exec 102 -- opkg install luci-i18n-base-zh-cn luci-i18n-firewall-zh-cn
pct exec 102 -- /etc/init.d/uhttpd restart
如果要安装主题,优先用官方源:
pct exec 102 -- opkg install luci-theme-material
pct exec 102 -- uci set luci.main.mediaurlbase='/luci-static/material'
pct exec 102 -- uci commit luci
pct exec 102 -- /etc/init.d/uhttpd restart
第三方 IPK 主题建议下载后先校验 hash,再安装。
创建 Kali 容器
Kali ARM64 模板也可以从 Linux Containers 镜像站找:
https://images.linuxcontainers.org/images/kali/current/arm64/default/
下载示例:
cd /var/lib/vz/template/cache
wget -O kali-current-arm64-default_YYYYMMDD_HHMM.tar.xz \
https://images.linuxcontainers.org/images/kali/current/arm64/default/YYYYMMDD_HH:MM/rootfs.tar.xz
校验示例:
wget -O /tmp/kali-SHA256SUMS \
https://images.linuxcontainers.org/images/kali/current/arm64/default/YYYYMMDD_HH:MM/SHA256SUMS
sha256sum kali-current-arm64-default_YYYYMMDD_HHMM.tar.xz
创建 Kali CT 示例:
pct create 103 local:vztmpl/kali-current-arm64-default_YYYYMMDD_HHMM.tar.xz \
--arch arm64 \
--ostype unmanaged \
--hostname kali \
--cores 1 \
--memory 4096 \
--swap 512 \
--rootfs local:12 \
--net0 name=eth0,bridge=vmbr0,ip=10.10.10.104/24,gw=10.10.10.1 \
--nameserver '1.1.1.1 8.8.8.8' \
--searchdomain local \
--unprivileged 0 \
--features nesting=1 \
--onboot 1
启动:
pct start 103
有些 ostype unmanaged 镜像不会自动应用 PVE 的 IPv4 配置。如果启动后发现只有 IPv6 link-local,需要在容器里写静态网络。
Kali 使用 systemd-networkd 的示例:
pct exec 103 -- bash -lc "cat > /etc/systemd/network/10-eth0.network <<'EOF'
[Match]
Name=eth0
[Network]
Address=10.10.10.104/24
Gateway=10.10.10.1
DNS=1.1.1.1
DNS=8.8.8.8
Domains=local
EOF
systemctl enable --now systemd-networkd
systemctl restart systemd-networkd
rm -f /etc/resolv.conf
printf 'search local\nnameserver 1.1.1.1\nnameserver 8.8.8.8\n' > /etc/resolv.conf"
Kali 的 DNS 可能优先返回 IPv6,但本文网络只有 IPv4 NAT。apt 可以强制 IPv4:
pct exec 103 -- bash -lc "printf 'Acquire::ForceIPv4 \"true\";\n' > /etc/apt/apt.conf.d/99-force-ipv4"
安装 SSH:
pct exec 103 -- bash -lc "apt-get -o Acquire::ForceIPv4=true update"
pct exec 103 -- bash -lc "DEBIAN_FRONTEND=noninteractive apt-get -o Acquire::ForceIPv4=true install -y openssh-server"
允许 root 密码登录:
pct exec 103 -- passwd root
pct exec 103 -- bash -lc "install -d -m 0755 /etc/ssh/sshd_config.d
cat > /etc/ssh/sshd_config.d/99-root-login.conf <<'EOF'
PermitRootLogin yes
PasswordAuthentication yes
EOF
systemctl enable --now ssh || service ssh start"
验证:
pct exec 103 -- ss -ltn | grep ':22 '
创建 Oracle Linux 容器
Oracle Linux ARM64 模板目录示例:
https://images.linuxcontainers.org/images/oracle/10/arm64/default/
下载:
cd /var/lib/vz/template/cache
wget -O oracle-10-arm64-default_YYYYMMDD_HHMM.tar.xz \
https://images.linuxcontainers.org/images/oracle/10/arm64/default/YYYYMMDD_HH:MM/rootfs.tar.xz
校验:
wget -O /tmp/oracle-SHA256SUMS \
https://images.linuxcontainers.org/images/oracle/10/arm64/default/YYYYMMDD_HH:MM/SHA256SUMS
sha256sum oracle-10-arm64-default_YYYYMMDD_HHMM.tar.xz
创建 Oracle Linux CT:
pct create 104 local:vztmpl/oracle-10-arm64-default_YYYYMMDD_HHMM.tar.xz \
--arch arm64 \
--ostype unmanaged \
--hostname oracle \
--cores 1 \
--memory 2048 \
--swap 512 \
--rootfs local:10 \
--net0 name=eth0,bridge=vmbr0,ip=10.10.10.105/24,gw=10.10.10.1 \
--nameserver '1.1.1.1 8.8.8.8' \
--searchdomain local \
--unprivileged 0 \
--features nesting=1 \
--onboot 1
启动:
pct start 104
如果没拿到 IPv4,可以用 NetworkManager 写静态配置:
pct exec 104 -- bash -lc "cat > /etc/NetworkManager/system-connections/eth0.nmconnection <<'EOF'
[connection]
id=eth0 type=ethernet interface-name=eth0 autoconnect=true
[ipv4]
method=manual addresses=10.10.10.105/24 gateway=10.10.10.1 dns=1.1.1.1;8.8.8.8; dns-search=local;
[ipv6]
method=ignore EOF chmod 600 /etc/NetworkManager/system-connections/eth0.nmconnection systemctl enable –now NetworkManager nmcli connection reload nmcli connection up eth0 || systemctl restart NetworkManager”
Oracle Linux 也建议强制 dnf 使用 IPv4:
pct exec 104 -- bash -lc "mkdir -p /etc/dnf/dnf.conf.d
printf 'ip_resolve=4\n' > /etc/dnf/dnf.conf.d/99-force-ipv4.conf"
安装 SSH:
pct exec 104 -- bash -lc "dnf -y --setopt=ip_resolve=4 install openssh-server"
允许 root 密码登录:
pct exec 104 -- passwd root
pct exec 104 -- bash -lc "install -d -m 0755 /etc/ssh/sshd_config.d
cat > /etc/ssh/sshd_config.d/99-root-login.conf <<'EOF'
PermitRootLogin yes
PasswordAuthentication yes
EOF
systemctl enable --now sshd || /usr/sbin/sshd"
验证:
pct exec 104 -- ss -ltn | grep ':22 '
注意:某些极简 Oracle Linux rootfs 可能没有 hostname 命令。这不影响 SSH。可以先写 /etc/hostname:
pct exec 104 -- sh -c "echo oracle > /etc/hostname"
容器 DNS 怎么填
本文宿主机只做 NAT,没有配置 DNS 转发服务。所以容器 DNS 不要填 10.10.10.1。
推荐:
DNS:1.1.1.1
备用 DNS:8.8.8.8
PVE 命令行可以写:
--nameserver '1.1.1.1 8.8.8.8'
PVE 面板里如果只有一个输入框,也可以填:
1.1.1.1 8.8.8.8
端口转发原理
容器在 10.10.10.0/24 私网里,外网不能直接访问。要让公网访问容器服务,需要在 PVE 宿主机上做两件事:
- DNAT:把宿主机公网高端口改写到容器 IP 和服务端口。
- FORWARD:允许这条转发流量通过宿主机。
以把容器 SSH 暴露出去为例:
公网访问:ssh -p <HOST_PORT> root@<PUBLIC_IP>
↓
宿主机 enp0s3 收到 TCP <HOST_PORT>
↓
iptables PREROUTING DNAT
↓
转发到 <CT_IP>:22
↓
容器 sshd 响应
以 Web 服务为例:
公网访问:http://<PUBLIC_IP>:<HOST_PORT>/
↓
宿主机 enp0s3 收到 TCP <HOST_PORT>
↓
DNAT 到 <CT_IP>:80
↓
容器 HTTP 服务响应
临时添加端口转发
示例 1:把 OpenWrt LuCI 从公网高端口转发到容器 80。
宿主公网端口:29971
容器 IP:10.10.10.103
容器服务端口:80
公网访问:http://<PUBLIC_IP>:29971/
命令:
iptables -t nat -A PREROUTING \
-i enp0s3 -p tcp --dport 29971 \
-j DNAT --to-destination 10.10.10.103:80
iptables -A FORWARD \
-i enp0s3 -o vmbr0 \
-p tcp -d 10.10.10.103 --dport 80 \
-j ACCEPT
示例 2:把 Kali SSH 转发出去。
宿主公网端口:21025
容器 IP:10.10.10.104
容器服务端口:22
公网访问:ssh -p 21025 root@<PUBLIC_IP>
命令:
iptables -t nat -A PREROUTING \
-i enp0s3 -p tcp --dport 21025 \
-j DNAT --to-destination 10.10.10.104:22
iptables -A FORWARD \
-i enp0s3 -o vmbr0 \
-p tcp -d 10.10.10.104 --dport 22 \
-j ACCEPT
示例 3:把 Oracle Linux SSH 转发出去。
宿主公网端口:36078
容器 IP:10.10.10.105
容器服务端口:22
公网访问:ssh -p 36078 root@<PUBLIC_IP>
命令:
iptables -t nat -A PREROUTING \
-i enp0s3 -p tcp --dport 36078 \
-j DNAT --to-destination 10.10.10.105:22
iptables -A FORWARD \
-i enp0s3 -o vmbr0 \
-p tcp -d 10.10.10.105 --dport 22 \
-j ACCEPT
这些规则是临时的,重启或网络重载后可能丢失。生产使用建议持久化。
持久化端口转发
本文采用把规则写进 /etc/network/interfaces 的 vmbr0 段。
改前先备份:
cp -a /etc/network/interfaces /etc/network/interfaces.backup.$(date +%Y%m%d-%H%M%S)
在 iface vmbr0 inet static 下面加入转发规则。
OpenWrt LuCI 示例:
# openwrt-luci-forward
post-up iptables -t nat -C PREROUTING -i enp0s3 -p tcp --dport 29971 -j DNAT --to-destination 10.10.10.103:80 2>/dev/null || iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 29971 -j DNAT --to-destination 10.10.10.103:80
post-up iptables -C FORWARD -i enp0s3 -o vmbr0 -p tcp -d 10.10.10.103 --dport 80 -j ACCEPT 2>/dev/null || iptables -A FORWARD -i enp0s3 -o vmbr0 -p tcp -d 10.10.10.103 --dport 80 -j ACCEPT
post-down iptables -t nat -D PREROUTING -i enp0s3 -p tcp --dport 29971 -j DNAT --to-destination 10.10.10.103:80 2>/dev/null || true
post-down iptables -D FORWARD -i enp0s3 -o vmbr0 -p tcp -d 10.10.10.103 --dport 80 -j ACCEPT 2>/dev/null || true
Kali SSH 示例:
# kali-ssh-forward
post-up iptables -t nat -C PREROUTING -i enp0s3 -p tcp --dport 21025 -j DNAT --to-destination 10.10.10.104:22 2>/dev/null || iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 21025 -j DNAT --to-destination 10.10.10.104:22
post-up iptables -C FORWARD -i enp0s3 -o vmbr0 -p tcp -d 10.10.10.104 --dport 22 -j ACCEPT 2>/dev/null || iptables -A FORWARD -i enp0s3 -o vmbr0 -p tcp -d 10.10.10.104 --dport 22 -j ACCEPT
post-down iptables -t nat -D PREROUTING -i enp0s3 -p tcp --dport 21025 -j DNAT --to-destination 10.10.10.104:22 2>/dev/null || true
post-down iptables -D FORWARD -i enp0s3 -o vmbr0 -p tcp -d 10.10.10.104 --dport 22 -j ACCEPT 2>/dev/null || true
Oracle Linux SSH 示例:
# oracle-ssh-forward
post-up iptables -t nat -C PREROUTING -i enp0s3 -p tcp --dport 36078 -j DNAT --to-destination 10.10.10.105:22 2>/dev/null || iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 36078 -j DNAT --to-destination 10.10.10.105:22
post-up iptables -C FORWARD -i enp0s3 -o vmbr0 -p tcp -d 10.10.10.105 --dport 22 -j ACCEPT 2>/dev/null || iptables -A FORWARD -i enp0s3 -o vmbr0 -p tcp -d 10.10.10.105 --dport 22 -j ACCEPT
post-down iptables -t nat -D PREROUTING -i enp0s3 -p tcp --dport 36078 -j DNAT --to-destination 10.10.10.105:22 2>/dev/null || true
post-down iptables -D FORWARD -i enp0s3 -o vmbr0 -p tcp -d 10.10.10.105 --dport 22 -j ACCEPT 2>/dev/null || true
这里的 -C ... || -A ... 是为了避免重复添加同一条规则。
选择公网高端口
建议用 10000 以上的随机端口,避开常见服务端口。
查看当前监听端口:
ss -ltn
查看已有 DNAT 端口:
iptables -t nat -S PREROUTING
随机挑一个端口:
shuf -i 10000-60999 -n 1
确认端口没被占用:
PORT=21025
ss -ltn | grep -q ":$PORT " && echo "port in use" || echo "port free"
iptables -t nat -S PREROUTING | grep -- "--dport $PORT " && echo "dnat exists" || echo "dnat free"
OCI 安全列表 / 网络安全组
宿主机 iptables 配好以后,OCI 侧也要放行对应公网端口。
例如你要访问:
ssh -p 21025 root@<PUBLIC_IP>
OCI 安全列表或 NSG 需要允许:
源:你的客户端 IP,或 0.0.0.0/0
协议:TCP
目标端口:21025
PVE 面板则需要允许:
TCP 8006
OpenWrt LuCI 示例需要允许:
TCP 29971
如果 iptables 没问题但公网访问不通,优先查 OCI 安全列表/NSG。
验证端口转发
验证容器服务是否监听:
pct exec 103 -- ss -ltn | grep ':22 '
pct exec 104 -- ss -ltn | grep ':22 '
pct exec 102 -- netstat -ltnp | grep ':80 '
验证宿主机规则:
iptables -t nat -S PREROUTING | grep 21025
iptables -S FORWARD | grep 10.10.10.104
从外部验证 SSH:
ssh -p 21025 root@<PUBLIC_IP>
ssh -p 36078 root@<PUBLIC_IP>
从外部验证 HTTP:
curl -I http://<PUBLIC_IP>:29971/
如果返回 HTTP/1.1 200 OK、302 或 LuCI 登录页内容,说明通了。
基础检查命令
查看容器列表:
pct list
查看容器配置:
pct config 103
进入容器:
pct enter 103
在容器里执行命令:
pct exec 103 -- uname -m
pct exec 103 -- cat /etc/os-release
检查 PVE 存储:
pvesm status
检查本地模板:
pveam list local
检查 bridge:
ip -br addr
bridge link
pvesh get /nodes/$(hostname)/network --type any_bridge
检查 NAT:
sysctl net.ipv4.ip_forward
iptables -t nat -S
iptables -S FORWARD
常见问题
PVE 创建 CT 时桥接下拉框没有 vmbr0
优先检查:
pvesh get /nodes/$(hostname)/network --type any_bridge
如果看不到 vmbr0,尝试:
- 把
vmbr0配置写入/etc/network/interfaces主文件。 - 不要只写在
/etc/network/interfaces.d/vmbr0。 - 给
vmbr0使用bridge-ports dummy0。 - 重启
pvedaemon和pveproxy。
systemctl restart pvedaemon pveproxy
ifupdown2 不接受 bridge-ports none
某些环境会报:
bridge-ports: invalid value "none"
可以改用 dummy0:
auto dummy0
iface dummy0 inet manual
pre-up ip link add dummy0 type dummy || true
post-down ip link delete dummy0 type dummy 2>/dev/null || true
auto vmbr0
iface vmbr0 inet static
address 10.10.10.1/24
bridge-ports dummy0
bridge-stp off
bridge-fd 0
容器没有 IPv4
如果 pct exec <VMID> -- ip addr 只看到 fe80::,说明镜像没有应用 PVE 注入的静态 IP。
处理方式:
- Debian/Kali 这类 systemd 镜像:写
/etc/systemd/network/10-eth0.network。 - Oracle Linux/Fedora 系:写 NetworkManager 连接文件。
- OpenWrt:改
/etc/config/network。
容器能 ping IP,不能解析域名
检查:
pct exec <VMID> -- cat /etc/resolv.conf
推荐写:
nameserver 1.1.1.1
nameserver 8.8.8.8
不要写 10.10.10.1,除非宿主机上配置了 DNS 转发。
Kali apt 解析到 IPv6 后失败
如果网络只有 IPv4 NAT,Kali apt 可能解析到 IPv6 地址后失败。强制 apt 用 IPv4:
pct exec 103 -- bash -lc "printf 'Acquire::ForceIPv4 \"true\";\n' > /etc/apt/apt.conf.d/99-force-ipv4"
然后:
pct exec 103 -- apt-get update
Oracle dnf 解析到 IPv6 后失败
强制 dnf 用 IPv4:
pct exec 104 -- bash -lc "mkdir -p /etc/dnf/dnf.conf.d
printf 'ip_resolve=4\n' > /etc/dnf/dnf.conf.d/99-force-ipv4.conf"
或者执行安装时临时加:
dnf -y --setopt=ip_resolve=4 install openssh-server
公网端口访问不通
按顺序查:
- OCI 安全列表或 NSG 是否放行
<HOST_PORT>。 - 宿主机
iptables -t nat -S PREROUTING是否有 DNAT。 - 宿主机
iptables -S FORWARD是否放行到容器。 net.ipv4.ip_forward是否为1。- 容器服务是否监听对应端口。
- 容器 IP 是否正确。
命令:
sysctl net.ipv4.ip_forward
iptables -t nat -S PREROUTING
iptables -S FORWARD
pct exec <VMID> -- ss -ltn
PVE 面板显示硬盘变小
50G 云盘在 Linux 里可能显示约 49G,这是 GB/GiB 换算差异。ext4 还会预留一部分空间给 root,PVE 本身也会占用几 GB。
这属于正常情况,不是硬盘真的变小。
一个完整例子
目标:
PVE 宿主公网 IP:<PUBLIC_IP>
LXC 网段:10.10.10.0/24
OpenWrt:102,10.10.10.103,LuCI 80 -> 公网 29971
Kali:103,10.10.10.104,SSH 22 -> 公网 21025
Oracle Linux:104,10.10.10.105,SSH 22 -> 公网 36078
公网访问方式:
# OpenWrt LuCI
http://<PUBLIC_IP>:29971/
# Kali SSH
ssh -p 21025 root@<PUBLIC_IP>
# Oracle Linux SSH
ssh -p 36078 root@<PUBLIC_IP>
宿主机持久化规则放在 /etc/network/interfaces 的 vmbr0 段,容器内部只需要确保服务监听自己的内网端口。
安全建议
- 不要把 root 密码写进公开教程。
- 公网 SSH 端口建议使用高端口,并在 OCI 安全列表里限制来源 IP。
- 如果长期使用,建议改成密钥登录,然后关闭密码登录。
- 公开 Web 面板前先设置强密码。
- 第三方 OpenWrt 主题或 IPK 包先校验 hash,再安装。
- 每次改
/etc/network/interfaces前先备份。 - 远程 reload 网络前确认有云控制台或救援方式。
总结
Oracle Cloud ARM 上安装 Proxmox VE 9 是可行的,但最适合作为 LXC 容器平台。
关键点:
- 用 Debian 13 trixie ARM64。
- 用 Proxmox VE 9 trixie arm64 源。
- 没有
/dev/kvm不影响 LXC。 - OCI 主网卡不要桥进
vmbr0。 - 容器使用
vmbr0+ IPv4 NAT 出网。 - 公网访问容器服务,在宿主机
enp0s3上做 DNAT + FORWARD。 - 转发规则写进
/etc/network/interfaces的vmbr0段持久化。 - ARM64 模板从 Linux Containers 镜像站下载,并尽量做 SHA256 校验。
这套方案不需要 DD 重装,风险比刷第三方镜像低,也更适合 OCI 这种云网络环境。

