Deploy AionUi WebUI on headless Linux servers — cloud VMs, Kubernetes Pods, and containers — with proxy auto-fallback support.
Translations: 中文版 below.
- Prerequisites
- Installation
- Virtual Display (Xvfb)
- Service Management Script
- Remote Access
- Proxy with Auto-Fallback
- Troubleshooting
- Architecture Overview
- Linux x86_64 (Ubuntu 20.04+ / Debian 11+ recommended)
- At least 2GB RAM
- AionUi
.debpackage from Releases
# Download the latest .deb package
wget https://github.com/iOfficeAI/AionUi/releases/latest/download/AionUi-linux-amd64.deb
# Install
sudo dpkg -i AionUi-linux-amd64.deb
sudo apt-get install -f # Fix missing dependenciesContainer note: If you encounter dependency errors for
libegl1/libgles2(common with NVIDIA runtime in containers), usedpkg --force-all -ito force install.
AionUi is an Electron app and requires a display server. On headless servers (no monitor), use Xvfb to create a virtual display:
sudo apt-get install -y xvfbXvfb is used automatically by the startup script below via xvfb-run.
Since many cloud/container environments lack systemd, use the following nohup-based script.
Create /opt/AionUi/start-aionui.sh:
#!/bin/bash
# AionUi WebUI headless startup script
# Usage: ./start-aionui.sh [start|stop|restart|status]
PIDFILE="/var/run/aionui.pid"
LOGFILE="/var/log/aionui.log"
WORKDIR="$HOME" # Change to your workspace directory
start() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat $PIDFILE)" 2>/dev/null; then
echo "AionUi is already running (PID: $(cat $PIDFILE))"
return 1
fi
echo "Starting AionUi WebUI..."
cd "$WORKDIR"
nohup xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" \
/usr/bin/AionUi --webui --remote --no-sandbox \
> "$LOGFILE" 2>&1 &
echo $! > "$PIDFILE"
sleep 3
if kill -0 "$(cat $PIDFILE)" 2>/dev/null; then
echo "AionUi started successfully (PID: $(cat $PIDFILE))"
echo "WebUI: http://$(hostname -I | awk '{print $1}'):25808"
else
echo "AionUi failed to start. Check log: $LOGFILE"
rm -f "$PIDFILE"
return 1
fi
}
stop() {
if [ ! -f "$PIDFILE" ]; then
echo "AionUi is not running (no PID file)"
return 1
fi
PID=$(cat "$PIDFILE")
echo "Stopping AionUi (PID: $PID)..."
kill "$PID" 2>/dev/null
sleep 2
kill -9 "$PID" 2>/dev/null
pkill -f "AionUi --webui" 2>/dev/null
rm -f "$PIDFILE"
echo "AionUi stopped."
}
restart() {
stop
sleep 1
start
}
status() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat $PIDFILE)" 2>/dev/null; then
echo "AionUi is running (PID: $(cat $PIDFILE))"
ss -tlnp | grep 25808
else
echo "AionUi is not running."
rm -f "$PIDFILE" 2>/dev/null
fi
}
case "${1:-start}" in
start) start ;;
stop) stop ;;
restart) restart ;;
status) status ;;
*) echo "Usage: $0 {start|stop|restart|status}" ;;
esacchmod +x /opt/AionUi/start-aionui.shTip:
WORKDIRdetermines the directory AionUi can access for file operations. Set it to your project workspace.
AionUi WebUI listens on port 25808. Choose a method based on your network setup:
Open port 25808 in your cloud provider's security group or firewall, then access via http://YOUR_SERVER_IP:25808.
pip3 install pyngrok
ngrok config add-authtoken YOUR_TOKEN
# Start tunnel
nohup ngrok http 25808 --log=stdout > /var/log/ngrok.log 2>&1 &
# Get public URL
curl -s http://127.0.0.1:4040/api/tunnels | python3 -c "
import sys, json
[print(t['public_url']) for t in json.load(sys.stdin)['tunnels']]
"Note: ngrok free tier generates a new URL on each restart. You can claim a free static domain at ngrok dashboard.
ssh -L 25808:127.0.0.1:25808 user@YOUR_SERVER_IP
# Then access: http://localhost:25808If your server needs a proxy for certain APIs (e.g., via an SSH reverse tunnel to a local VPN), use the PAC auto-fallback approach: try proxy first, fall back to direct connection when the proxy is unavailable. No restart needed.
Forward your local proxy port to the server:
ssh -R 7897:127.0.0.1:7897 user@YOUR_SERVER_IPReplace
7897with your actual proxy port. The tunnel is active as long as the SSH session is open.
Using --proxy-server is fragile — when the proxy goes down, all requests fail including the WebUI itself. Instead, use a PAC (Proxy Auto-Configuration) file that provides automatic fallback.
Create /opt/AionUi/proxy.pac:
function FindProxyForURL(url, host) {
// Localhost and private networks: always direct
if (isPlainHostName(host) ||
host === "127.0.0.1" ||
host === "localhost" ||
shExpMatch(host, "10.*") ||
shExpMatch(host, "192.168.*") ||
shExpMatch(host, "172.16.*")) {
return "DIRECT";
}
// All other requests: try proxy first, fallback to direct
return "PROXY 127.0.0.1:7897; DIRECT";
}Then update the nohup xvfb-run ... line in your startup script:
nohup xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" \
/usr/bin/AionUi --webui --remote --no-sandbox \
--proxy-pac-url="file:///opt/AionUi/proxy.pac" \
> "$LOGFILE" 2>&1 &How it works:
- Chromium natively supports PAC proxy rules
"PROXY 127.0.0.1:7897; DIRECT"means: try the proxy, and if it fails (connection refused / timeout), automatically fall back to a direct connection- Failover is per-request and real-time — no restart needed when the SSH tunnel connects or disconnects
Shell tools like curl and wget use http_proxy environment variables. Add automatic detection to ~/.bashrc so the proxy env vars are set/unset dynamically before every command:
# === Proxy Auto-Detect ===
_auto_proxy() {
if (echo > /dev/tcp/127.0.0.1/7897) 2>/dev/null; then
export http_proxy=http://127.0.0.1:7897
export https_proxy=http://127.0.0.1:7897
export ALL_PROXY=socks5://127.0.0.1:7897
else
unset http_proxy https_proxy ALL_PROXY 2>/dev/null
fi
}
_auto_proxy
PROMPT_COMMAND="_auto_proxy;${PROMPT_COMMAND}"
# === Proxy Auto-Detect End ===How it works:
PROMPT_COMMANDruns before every shell prompt, re-checking proxy availability- SSH tunnel connected → proxy env vars set automatically
- SSH tunnel disconnected → proxy env vars cleared, commands use direct connection
- No manual intervention or terminal restart needed
For Gemini API calls, configure the proxy inside AionUi WebUI:
Settings → Gemini Settings → Proxy → http://127.0.0.1:7897
This proxy is handled by AionUi's Node.js layer (separate from the Chromium layer). When the SSH tunnel is down, Gemini API calls will fail, but the WebUI and other APIs remain functional.
| Issue | Solution |
|---|---|
dpkg dependency errors in containers |
dpkg --force-all -i AionUi-linux-amd64.deb |
AionUi can only access /tmp |
Set WORKDIR in the startup script to your workspace path |
| WebUI not accessible remotely | Check firewall rules, or use ngrok / SSH tunnel |
| All requests fail when proxy is down | Use PAC file (--proxy-pac-url) instead of --proxy-server |
curl fails after SSH tunnel disconnects |
Add PROMPT_COMMAND auto-detect to ~/.bashrc (see Step 3) |
| Port 25808 already in use | kill $(lsof -t -i:25808) then restart |
| Xvfb errors | apt-get install -y xvfb libxkbcommon-x11-0 |
┌──────────────────────────────────────────────────┐
│ Headless Linux Server / Container │
│ │
│ start-aionui.sh │
│ │ │
│ ▼ │
│ xvfb-run (virtual display) │
│ │ │
│ ▼ │
│ ┌────────────────────────────┐ │
│ │ AionUi (Electron) │ │
│ │ ├─ Chromium (port 25808) │ │
│ │ │ └─ proxy.pac │──► PAC decides: │
│ │ │ per-request │ PROXY or DIRECT │
│ │ └─ Node.js (API calls) │ │
│ └────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────┐ │
│ │ SSH Reverse Tunnel │ │
│ │ 127.0.0.1:7897 │ │
│ │ (when available) │ │
│ └─────────────────────────┘ │
│ │ │
│ ┌────────┴───────┐ │
│ │ ngrok tunnel │ (optional, for public URL) │
│ └────────────────┘ │
└──────────────────────────────────────────────────┘
在无图形界面的 Linux 服务器(云主机、K8s Pod、容器)上部署 AionUi WebUI,支持代理自动回退。
- Linux x86_64(推荐 Ubuntu 20.04+ / Debian 11+)
- 至少 2GB 内存
- AionUi
.deb安装包(下载地址)
# 下载最新 .deb 包
wget https://github.com/iOfficeAI/AionUi/releases/latest/download/AionUi-linux-amd64.deb
# 安装
sudo dpkg -i AionUi-linux-amd64.deb
sudo apt-get install -f # 修复依赖容器环境:若遇到
libegl1/libgles2依赖错误(常见于 NVIDIA 运行时),可用dpkg --force-all -i强制安装。
AionUi 是 Electron 应用,需要显示服务。无头服务器需安装 Xvfb:
sudo apt-get install -y xvfb许多云/容器环境没有 systemd,使用以下基于 nohup 的管理脚本。
创建 /opt/AionUi/start-aionui.sh:
#!/bin/bash
# AionUi WebUI 无头启动脚本
# 用法: ./start-aionui.sh [start|stop|restart|status]
PIDFILE="/var/run/aionui.pid"
LOGFILE="/var/log/aionui.log"
WORKDIR="$HOME" # 改为你的工作目录
start() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat $PIDFILE)" 2>/dev/null; then
echo "AionUi 已在运行 (PID: $(cat $PIDFILE))"
return 1
fi
echo "正在启动 AionUi WebUI..."
cd "$WORKDIR"
nohup xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" \
/usr/bin/AionUi --webui --remote --no-sandbox \
> "$LOGFILE" 2>&1 &
echo $! > "$PIDFILE"
sleep 3
if kill -0 "$(cat $PIDFILE)" 2>/dev/null; then
echo "AionUi 启动成功 (PID: $(cat $PIDFILE))"
echo "WebUI: http://$(hostname -I | awk '{print $1}'):25808"
else
echo "AionUi 启动失败,请查看日志: $LOGFILE"
rm -f "$PIDFILE"
return 1
fi
}
stop() {
if [ ! -f "$PIDFILE" ]; then
echo "AionUi 未在运行"
return 1
fi
PID=$(cat "$PIDFILE")
echo "正在停止 AionUi (PID: $PID)..."
kill "$PID" 2>/dev/null
sleep 2
kill -9 "$PID" 2>/dev/null
pkill -f "AionUi --webui" 2>/dev/null
rm -f "$PIDFILE"
echo "AionUi 已停止。"
}
restart() { stop; sleep 1; start; }
status() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat $PIDFILE)" 2>/dev/null; then
echo "AionUi 运行中 (PID: $(cat $PIDFILE))"
ss -tlnp | grep 25808
else
echo "AionUi 未在运行。"
rm -f "$PIDFILE" 2>/dev/null
fi
}
case "${1:-start}" in
start) start ;; stop) stop ;; restart) restart ;; status) status ;;
*) echo "用法: $0 {start|stop|restart|status}" ;;
esacAionUi WebUI 监听端口 25808,根据网络环境选择访问方式:
| 方式 | 适用场景 | 命令 |
|---|---|---|
| 直接访问 | 有公网 IP | 安全组开放 25808 端口 |
| ngrok 穿透 | NAT / K8s / 无公网 IP | ngrok http 25808 |
| SSH 隧道 | 仅个人使用 | ssh -L 25808:127.0.0.1:25808 user@server |
当服务器需要通过代理访问某些 API(如通过 SSH 反向隧道连接本地 VPN)时,使用 PAC 自动回退:代理可用时走代理,不可用时自动直连,无需重启。
ssh -R 7897:127.0.0.1:7897 user@YOUR_SERVER--proxy-server 的问题:代理一断,所有请求全挂。改用 PAC 文件实现自动回退。
创建 /opt/AionUi/proxy.pac:
function FindProxyForURL(url, host) {
if (isPlainHostName(host) ||
host === "127.0.0.1" ||
host === "localhost" ||
shExpMatch(host, "10.*") ||
shExpMatch(host, "192.168.*") ||
shExpMatch(host, "172.16.*")) {
return "DIRECT";
}
return "PROXY 127.0.0.1:7897; DIRECT";
}启动脚本中添加参数:--proxy-pac-url="file:///opt/AionUi/proxy.pac"
原理:Chromium 原生支持 PAC,PROXY ...; DIRECT 表示先尝试代理,失败自动直连,每个请求实时判断。
在 ~/.bashrc 中添加,让 curl 等命令也能自动检测代理:
# === Proxy Auto-Detect ===
_auto_proxy() {
if (echo > /dev/tcp/127.0.0.1/7897) 2>/dev/null; then
export http_proxy=http://127.0.0.1:7897
export https_proxy=http://127.0.0.1:7897
export ALL_PROXY=socks5://127.0.0.1:7897
else
unset http_proxy https_proxy ALL_PROXY 2>/dev/null
fi
}
_auto_proxy
PROMPT_COMMAND="_auto_proxy;${PROMPT_COMMAND}"
# === Proxy Auto-Detect End ===原理:PROMPT_COMMAND 在每次命令提示符前执行,自动检测代理端口是否可达,实时切换。
在 WebUI 中设置:Settings → Gemini Settings → Proxy → http://127.0.0.1:7897
此代理由 Node.js 层处理,独立于 Chromium。隧道断开时仅 Gemini API 受影响。
| 问题 | 解决方案 |
|---|---|
| 容器内 dpkg 依赖报错 | dpkg --force-all -i 强制安装 |
| AionUi 只能访问 /tmp | 修改启动脚本中的 WORKDIR |
| 远程无法访问 WebUI | 检查防火墙/安全组,或使用 ngrok |
| 代理断开后所有请求失败 | 用 PAC 文件替代 --proxy-server |
| SSH 断开后 curl 失败 | bashrc 添加 PROMPT_COMMAND 自动检测 |
| 端口 25808 被占用 | kill $(lsof -t -i:25808) 后重启 |