setup-sudo.sh
Rama main · réplica de lectura del repositorio original.
#!/bin/bash
# =============================================================================
# OpenVoiceUI — generic sudo setup script
# Creates: nginx config, Let's Encrypt SSL, systemd service, prestart script
# Run as: sudo bash setup-sudo.sh
# =============================================================================
set -e
# ── Configure these before running ──────────────────────────────────────────
INSTALL_DIR="$(cd "$(dirname "$0")" && pwd)"
DOMAIN="your-domain.com" # ← EDIT: your actual domain
PORT=5001 # ← match PORT in your .env (default: 5001)
EMAIL="your@email.com" # ← EDIT: for Let's Encrypt notifications
SERVICE_NAME="openvoiceui"
RUN_USER="${SUDO_USER:-$(whoami)}"
WWW_DIR="/var/www/${SERVICE_NAME}" # canvas pages + any web assets
OPENCLAW_TESTED_VERSION="2026.5.7" # pinned: the openclaw version tested with this release
# ────────────────────────────────────────────────────────────────────────────
# Guard: refuse to run with placeholder values
if [ "$DOMAIN" = "your-domain.com" ] || [ "$EMAIL" = "your@email.com" ]; then
echo "ERROR: Edit DOMAIN and EMAIL at the top of this script before running."
echo " Open setup-sudo.sh in a text editor and set your real domain and email."
exit 1
fi
# Check .env exists
if [ ! -f "${INSTALL_DIR}/.env" ]; then
echo "ERROR: No .env file found at ${INSTALL_DIR}/.env"
echo " Run: cp ${INSTALL_DIR}/.env.example ${INSTALL_DIR}/.env"
echo " Then edit .env and set your API keys before running this script."
exit 1
fi
# ── OpenClaw gateway setup ────────────────────────────────────────────────────
# Helper: is OpenClaw currently listening on its default port?
_openclaw_running() {
ss -tlnp 2>/dev/null | grep -q ':18791'
}
# Helper: is the openclaw binary installed anywhere?
_openclaw_installed() {
command -v openclaw >/dev/null 2>&1 \
|| [ -f "/usr/local/bin/openclaw" ] \
|| [ -f "${HOME}/.local/bin/openclaw" ]
}
# Helper: get installed openclaw version string (e.g. "2026.3.2")
_openclaw_version() {
local ver=""
if command -v openclaw >/dev/null 2>&1; then
ver=$(openclaw --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
elif [ -f "/usr/local/bin/openclaw" ]; then
ver=$(/usr/local/bin/openclaw --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
elif [ -f "${HOME}/.local/bin/openclaw" ]; then
ver=$(${HOME}/.local/bin/openclaw --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
fi
echo "$ver"
}
# Helper: compare two version strings (format: YYYY.M.D)
# Returns: 0 = match, 1 = first is newer, 2 = first is older
_version_compare() {
local a="$1" b="$2"
if [ "$a" = "$b" ]; then return 0; fi
local older
older=$(printf '%s\n%s' "$a" "$b" | sort -V | head -n1)
if [ "$older" = "$a" ]; then return 2; else return 1; fi
}
# Helper: display the requirements checklist for existing openclaw installs
_show_requirements() {
echo ""
echo " ┌────────────────────────────────────────────────────────────────────┐"
echo " │ OpenVoiceUI Gateway Requirements │"
echo " │ │"
echo " │ Your openclaw.json must include these settings for voice to work. │"
echo " │ OpenVoiceUI will NOT modify your config — these are for you to │"
echo " │ review and apply manually. │"
echo " │ │"
echo " │ VERSION │"
echo " │ Tested: openclaw@${OPENCLAW_TESTED_VERSION} │"
echo " │ Other versions may work but are not guaranteed. │"
echo " │ │"
echo " │ GATEWAY (global — affects all agents on this instance) │"
echo " │ gateway.auth.mode: \"token\" │"
echo " │ gateway.controlUi.dangerouslyDisableDeviceAuth: true │"
echo " │ │"
echo " │ AGENT (can be scoped to the openvoiceui agent only) │"
echo " │ agents.defaults.thinkingDefault: \"off\" │"
echo " │ agents.defaults.blockStreamingDefault: \"on\" │"
echo " │ agents.defaults.timeoutSeconds: 300 │"
echo " │ agents.defaults.compaction.reserveTokensFloor: 120000 │"
echo " │ │"
echo " │ Full details: docs/openclaw-requirements.md │"
echo " └────────────────────────────────────────────────────────────────────┘"
echo ""
}
echo ""
echo "── OpenClaw Gateway ──────────────────────────────────────────────────────"
echo ""
echo " OpenVoiceUI uses OpenClaw as its AI gateway for voice conversations."
echo " Tested version: openclaw@${OPENCLAW_TESTED_VERSION}"
echo ""
OPENCLAW_GATEWAY_URL=$(grep -E "^CLAWDBOT_GATEWAY_URL=" "${INSTALL_DIR}/.env" 2>/dev/null | cut -d= -f2 | tr -d '"' | tr -d "'")
OPENCLAW_GATEWAY_URL="${OPENCLAW_GATEWAY_URL:-ws://127.0.0.1:18791}"
OPENCLAW_TOKEN=$(grep -E "^CLAWDBOT_AUTH_TOKEN=" "${INSTALL_DIR}/.env" 2>/dev/null | cut -d= -f2 | tr -d '"' | tr -d "'")
OPENCLAW_CONFIGURED=false
# Detect current state
HAS_RUNNING=false
HAS_INSTALLED=false
INSTALLED_VERSION=""
if _openclaw_running; then HAS_RUNNING=true; HAS_INSTALLED=true; fi
if _openclaw_installed; then HAS_INSTALLED=true; fi
if [ "$HAS_INSTALLED" = "true" ]; then
INSTALLED_VERSION=$(_openclaw_version)
fi
# Show options based on current state
if [ "$HAS_RUNNING" = "true" ] || [ "$HAS_INSTALLED" = "true" ]; then
echo " Detected: OpenClaw is installed on this system."
[ -n "$INSTALLED_VERSION" ] && echo " Installed version: ${INSTALLED_VERSION}"
[ "$HAS_RUNNING" = "true" ] && echo " Status: running (port 18791 active)"
echo ""
echo " How would you like to set up the gateway?"
echo ""
echo " 1) Install a fresh OpenClaw for OpenVoiceUI (recommended)"
echo " Installs openclaw@${OPENCLAW_TESTED_VERSION} alongside your existing install."
echo " This will replace the globally installed version."
echo ""
echo " 2) Use my existing OpenClaw"
echo " You must configure it yourself to meet OpenVoiceUI's requirements."
echo " Voice features may not work if settings don't match."
echo ""
echo " 3) Skip — I'll set up the gateway later"
echo ""
printf " Choice [1]: "
read -r CHOICE
CHOICE="${CHOICE:-1}"
else
echo " OpenClaw is not installed on this system."
echo ""
echo " How would you like to set up the gateway?"
echo ""
echo " 1) Install OpenClaw now (recommended)"
echo " Installs openclaw@${OPENCLAW_TESTED_VERSION} configured for voice conversations."
echo ""
echo " 2) Skip — I'll install and configure OpenClaw later"
echo ""
printf " Choice [1]: "
read -r CHOICE
CHOICE="${CHOICE:-1}"
# Map choice 2 to "skip" (choice 3 in the full menu)
if [ "$CHOICE" = "2" ]; then CHOICE="3"; fi
fi
case "$CHOICE" in
1)
# ── Fresh install ──────────────────────────────────────────────────
echo ""
echo " Installing openclaw@${OPENCLAW_TESTED_VERSION}..."
# Check for npm/pnpm
if command -v pnpm >/dev/null 2>&1; then
PKG_MGR="pnpm"
INSTALL_CMD="pnpm add -g openclaw@${OPENCLAW_TESTED_VERSION}"
elif command -v npm >/dev/null 2>&1; then
PKG_MGR="npm"
INSTALL_CMD="npm i -g openclaw@${OPENCLAW_TESTED_VERSION}"
else
echo " ⚠ Neither npm nor pnpm found. Install Node.js 22+ first:"
echo " curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -"
echo " sudo apt install -y nodejs"
echo " Then re-run this script."
exit 1
fi
echo " Using ${PKG_MGR}..."
if $INSTALL_CMD; then
echo " ✓ openclaw@${OPENCLAW_TESTED_VERSION} installed."
else
echo " ⚠ Installation failed. Check the output above for errors."
echo " You can install manually: ${INSTALL_CMD}"
printf " Continue setup without the gateway? [y/N] "
read -r REPLY
if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1; fi
fi
if _openclaw_installed; then
# Run onboard wizard if no config exists yet
OPENCLAW_HOME="$(eval echo "~${RUN_USER}")/.openclaw"
if [ ! -f "${OPENCLAW_HOME}/openclaw.json" ]; then
echo ""
echo " ── OpenClaw First-Time Setup ───────────────────────────────────"
echo " OpenClaw needs to know which AI model to use."
echo " The setup wizard will ask for your LLM provider and API key."
echo " ────────────────────────────────────────────────────────────────"
echo ""
# Run onboard as the service user, not root
sudo -u "${RUN_USER}" openclaw onboard 2>&1 || true
fi
# Start the gateway
echo ""
echo " Starting OpenClaw gateway..."
if ! _openclaw_running; then
sudo -u "${RUN_USER}" openclaw gateway &
WAIT_I=0
while [ $WAIT_I -lt 10 ]; do
sleep 1
_openclaw_running && break
WAIT_I=$((WAIT_I+1))
done
fi
if _openclaw_running; then
echo " ✓ OpenClaw gateway is running on port 18791."
OPENCLAW_CONFIGURED=true
else
echo " ⚠ Gateway did not start. You can start it manually later:"
echo " openclaw gateway"
fi
fi
;;
2)
# ── Use existing install ───────────────────────────────────────────
echo ""
echo " Using your existing OpenClaw installation."
# Version check
if [ -n "$INSTALLED_VERSION" ]; then
_version_compare "$INSTALLED_VERSION" "$OPENCLAW_TESTED_VERSION"
VERSION_CMP=$?
if [ $VERSION_CMP -ne 0 ]; then
echo ""
echo " ┌────────────────────────────────────────────────────────────────┐"
echo " │ ⚠ VERSION MISMATCH │"
echo " │ │"
printf " │ %-62s │\n" "Your version: openclaw@${INSTALLED_VERSION}"
printf " │ %-62s │\n" "Tested version: openclaw@${OPENCLAW_TESTED_VERSION}"
echo " │ │"
if [ $VERSION_CMP -eq 1 ]; then
echo " │ Your version is NEWER and may include breaking changes │"
echo " │ (especially around auth and config validation). │"
else
echo " │ Your version is OLDER and may be missing required features. │"
fi
echo " │ Voice conversations may not work correctly. │"
echo " │ │"
printf " │ %-62s │\n" "To install the tested version:"
printf " │ %-62s │\n" " npm i -g openclaw@${OPENCLAW_TESTED_VERSION}"
echo " └────────────────────────────────────────────────────────────────┘"
echo ""
printf " Continue with openclaw@${INSTALLED_VERSION} anyway? [y/N] "
read -r REPLY
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo " Stopping. Install the tested version and re-run this script."
exit 1
fi
else
echo " ✓ Version matches (${INSTALLED_VERSION})."
fi
fi
# Show requirements checklist
_show_requirements
echo " Please review the requirements above and confirm your OpenClaw"
echo " is configured to meet them. OpenVoiceUI will NOT modify your"
echo " OpenClaw config."
echo ""
printf " I've reviewed the requirements and my OpenClaw is configured [y/N]: "
read -r REPLY
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo ""
echo " No problem. Configure your OpenClaw to meet the requirements,"
echo " then re-run this script. Or choose option 1 for a fresh install."
exit 1
fi
# Try to use it
if [ "$HAS_RUNNING" = "true" ]; then
OPENCLAW_CONFIGURED=true
elif _openclaw_installed; then
echo " OpenClaw is not currently running."
printf " Start it now? [Y/n] "
read -r REPLY
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
echo " Starting..."
sudo -u "${RUN_USER}" openclaw gateway &
sleep 5
if _openclaw_running; then
echo " ✓ OpenClaw started."
OPENCLAW_CONFIGURED=true
else
echo " ⚠ Could not start. Start it manually, then restart OpenVoiceUI."
fi
fi
fi
# Custom gateway URL
if [ "$OPENCLAW_CONFIGURED" = "true" ]; then
printf " Gateway URL [${OPENCLAW_GATEWAY_URL}]: "
read -r CUSTOM_URL
if [ -n "$CUSTOM_URL" ]; then
sed -i "s|^CLAWDBOT_GATEWAY_URL=.*|CLAWDBOT_GATEWAY_URL=${CUSTOM_URL}|" "${INSTALL_DIR}/.env"
OPENCLAW_GATEWAY_URL="$CUSTOM_URL"
echo " Updated CLAWDBOT_GATEWAY_URL in .env"
fi
fi
;;
3|*)
# ── Skip ───────────────────────────────────────────────────────────
echo ""
echo " ┌────────────────────────────────────────────────────────────────┐"
echo " │ OpenVoiceUI needs an AI gateway for voice conversations. │"
echo " │ Without one the server will start but the voice agent will │"
echo " │ not respond to any input. │"
echo " │ │"
echo " │ To set up later: │"
echo " │ 1. Install: npm i -g openclaw@${OPENCLAW_TESTED_VERSION} │"
echo " │ 2. Run: openclaw onboard │"
echo " │ 3. Set CLAWDBOT_AUTH_TOKEN in .env │"
echo " │ 4. Restart: sudo systemctl restart openvoiceui │"
echo " │ │"
echo " │ Or use Docker instead (includes everything): │"
echo " │ docker compose up --build │"
echo " └────────────────────────────────────────────────────────────────┘"
echo ""
printf " Continue setup without a gateway? [y/N] "
read -r REPLY
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Stopping."
exit 1
fi
echo " Continuing — voice conversations will not work until a gateway is configured."
;;
esac
# Check auth token is set and not placeholder
if [ "$OPENCLAW_CONFIGURED" = "true" ]; then
if [ -z "$OPENCLAW_TOKEN" ] || [ "$OPENCLAW_TOKEN" = "your-openclaw-gateway-token" ]; then
echo ""
echo " ⚠ CLAWDBOT_AUTH_TOKEN is not set in .env."
echo " OpenClaw is running but OpenVoiceUI cannot authenticate to it."
echo " Copy your agent auth token from your OpenClaw workspace and set:"
echo " CLAWDBOT_AUTH_TOKEN=your-token-here"
echo " in ${INSTALL_DIR}/.env, then restart the service."
else
echo " ✓ Auth token configured. Gateway: ${OPENCLAW_GATEWAY_URL}"
fi
echo ""
echo " Note: The AI model (LLM) is configured inside your OpenClaw agent"
echo " workspace — OpenVoiceUI works with any model OpenClaw is connected to."
echo " Voice settings (TTS, profile, wake words) are in the admin dashboard:"
echo " https://${DOMAIN}/src/admin.html"
fi
echo ""
echo "=== OpenVoiceUI setup: ${DOMAIN} on port ${PORT} ==="
echo " Install dir : ${INSTALL_DIR}"
echo " Service user: ${RUN_USER}"
echo " WWW dir : ${WWW_DIR}"
echo ""
# 0. Per-instance www directory (canvas pages, isolated from other users)
echo "[0/6] Creating www directory for ${RUN_USER}..."
mkdir -p "${WWW_DIR}/canvas-pages"
chown -R "${RUN_USER}:${RUN_USER}" "${WWW_DIR}"
chmod -R 755 "${WWW_DIR}"
# 0b. OpenVoiceUI agent workspace (dedicated agent — does NOT touch user's main agent)
OPENCLAW_DIR="$(eval echo "~${RUN_USER}")/.openclaw"
AGENT_TEMPLATE_DIR="${INSTALL_DIR}/setup/openvoiceui-agent"
AGENT_DEST_DIR="${OPENCLAW_DIR}/agents/openvoiceui"
if [ -d "${AGENT_TEMPLATE_DIR}" ] && [ -d "${OPENCLAW_DIR}" ]; then
if [ -d "${AGENT_DEST_DIR}" ]; then
echo " OpenVoiceUI agent already exists at ${AGENT_DEST_DIR} — skipping (not overwriting)"
else
echo " Creating OpenVoiceUI agent workspace at ${AGENT_DEST_DIR}..."
mkdir -p "${AGENT_DEST_DIR}/memory"
for f in SOUL.md TOOLS.md AGENTS.md IDENTITY.md MEMORY.md USER.md; do
if [ -f "${AGENT_TEMPLATE_DIR}/${f}" ]; then
# Fill in instance-specific placeholder values
sed "s|{{CANVAS_PAGES_DIR}}|${WWW_DIR}/canvas-pages|g" \
"${AGENT_TEMPLATE_DIR}/${f}" > "${AGENT_DEST_DIR}/${f}"
fi
done
chown -R "${RUN_USER}:${RUN_USER}" "${AGENT_DEST_DIR}"
echo " Agent workspace created. Register it in ~/.openclaw/openclaw.json:"
echo " { id: \"openvoiceui\", workspace: \"${AGENT_DEST_DIR}\", model: { primary: \"your-model\" } }"
echo " Then set VOICE_SESSION_PREFIX=voice-openvoiceui in your .env"
fi
# transcripts: let the agent READ its own voice transcripts. They are written by the
# OpenVoiceUI app (its runtime transcripts dir) but the agent only sees its workspace —
# so without this link a transcript/note "sent to the AI" is invisible to it. Runs whether
# the agent workspace is fresh or pre-existing (idempotent). Added 2026-06-11.
if [ -d "${AGENT_DEST_DIR}" ]; then
mkdir -p "${WWW_DIR}/transcripts"
chown -R "${RUN_USER}:${RUN_USER}" "${WWW_DIR}/transcripts" 2>/dev/null || true
ln -sfn "${WWW_DIR}/transcripts" "${AGENT_DEST_DIR}/transcripts"
echo " Linked transcripts into agent workspace (${AGENT_DEST_DIR}/transcripts → ${WWW_DIR}/transcripts)"
fi
elif [ ! -d "${OPENCLAW_DIR}" ]; then
echo " OpenClaw not configured yet (~/.openclaw missing) — skipping agent setup"
echo " Run setup again after configuring OpenClaw, or manually copy setup/openvoiceui-agent/"
fi
# 0c. Bundled agent skills (./skills) -> OpenClaw's managed skills dir, in a subfolder the
# installer owns: ~/.openclaw/skills/openvoiceui/<skill>/SKILL.md. OpenClaw scans that dir by
# default (no openclaw.json change). Re-running is safe: unchanged files update, files you
# edited are kept, nothing is deleted. After `git pull`, refresh with:
# node install-skills.js
# Copied, not symlinked: OpenClaw skips skill paths that resolve outside their skills root.
SKILLS_TARGET="${OPENCLAW_DIR}/skills/openvoiceui"
if [ ! -d "${OPENCLAW_DIR}" ]; then
echo " OpenClaw not configured yet — skipping bundled skills."
echo " Install them later (as ${RUN_USER}): node ${INSTALL_DIR}/install-skills.js"
elif ! command -v node >/dev/null 2>&1; then
echo " ⚠ node not found — skipping bundled skills."
echo " Install them later (as ${RUN_USER}): node ${INSTALL_DIR}/install-skills.js"
else
echo " Installing bundled agent skills into ${SKILLS_TARGET}..."
if ! sudo -u "${RUN_USER}" -H node "${INSTALL_DIR}/install-skills.js" --target "${SKILLS_TARGET}"; then
echo " ⚠ Skill install failed (non-fatal). Retry as ${RUN_USER}: node ${INSTALL_DIR}/install-skills.js"
fi
fi
# 1. Prestart script (kills stale process on port before service starts)
echo "[1/6] Creating prestart script..."
cat > /usr/local/bin/prestart-${SERVICE_NAME}.sh << PRESTART
#!/bin/bash
PORT=${PORT}
LOG=/var/log/${SERVICE_NAME}.log
PID=\$(fuser \${PORT}/tcp 2>/dev/null)
if [ -n "\$PID" ]; then
echo "\$(date): Found stale process \$PID on port \$PORT, killing..." | tee -a \$LOG
kill \$PID 2>/dev/null
sleep 2
if kill -0 \$PID 2>/dev/null; then
kill -9 \$PID 2>/dev/null
sleep 1
fi
fi
exit 0
PRESTART
chmod +x /usr/local/bin/prestart-${SERVICE_NAME}.sh
# 2. Systemd service
echo "[2/6] Creating systemd service..."
cat > /etc/systemd/system/${SERVICE_NAME}.service << SERVICE
[Unit]
Description=OpenVoiceUI Voice Agent (${DOMAIN})
After=network.target
[Service]
Type=simple
User=${RUN_USER}
WorkingDirectory=${INSTALL_DIR}
ExecStartPre=/usr/local/bin/prestart-${SERVICE_NAME}.sh
ExecStart=${INSTALL_DIR}/venv/bin/python3 ${INSTALL_DIR}/server.py
Restart=on-failure
RestartSec=10
Environment=PATH=/usr/bin:/usr/local/bin
EnvironmentFile=${INSTALL_DIR}/.env
[Install]
WantedBy=multi-user.target
SERVICE
# 3. Nginx config
# 3a. Write HTTP-only nginx config so certbot can serve ACME challenges
echo "[3/6] Creating nginx config..."
if [ ! -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]; then
echo " No SSL cert yet -- writing HTTP-only config for certbot..."
cat > /etc/nginx/sites-available/${DOMAIN} << NGINX
server {
listen 80;
listen [::]:80;
server_name ${DOMAIN};
location / {
proxy_pass http://127.0.0.1:${PORT};
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_cache_bypass \$http_upgrade;
proxy_read_timeout 86400;
}
client_max_body_size 25M;
}
NGINX
ln -sf /etc/nginx/sites-available/${DOMAIN} /etc/nginx/sites-enabled/${DOMAIN}
nginx -t
systemctl reload nginx
# 4. Obtain SSL cert (nginx can now serve ACME challenge on port 80)
echo "[4/6] Obtaining SSL certificate..."
certbot certonly --nginx -d ${DOMAIN} --non-interactive --agree-tos -m ${EMAIL}
else
echo " SSL cert already exists, skipping certbot."
fi
# 3b. Write full HTTPS config (cert now exists)
echo " Writing HTTPS nginx config..."
cat > /etc/nginx/sites-available/${DOMAIN} << NGINX
server {
listen 80;
listen [::]:80;
server_name ${DOMAIN};
return 301 https://\$host\$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ${DOMAIN};
ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://127.0.0.1:${PORT};
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_cache_bypass \$http_upgrade;
proxy_read_timeout 86400;
}
client_max_body_size 25M;
}
NGINX
ln -sf /etc/nginx/sites-available/${DOMAIN} /etc/nginx/sites-enabled/${DOMAIN}
# 5. Enable and start service
echo "[5/6] Enabling and starting service..."
nginx -t
systemctl reload nginx
systemctl daemon-reload
systemctl enable ${SERVICE_NAME}.service
systemctl restart ${SERVICE_NAME}.service
sleep 3
systemctl status ${SERVICE_NAME}.service --no-pager
echo "[6/6] Setup complete."
echo ""
echo "=== Done! OpenVoiceUI running at https://${DOMAIN} ==="
echo ""
echo "Useful commands:"
echo " sudo systemctl status ${SERVICE_NAME}"
echo " sudo systemctl restart ${SERVICE_NAME}"
echo " sudo journalctl -u ${SERVICE_NAME} -f"