Update onepush.sh
This commit is contained in:
parent
1e336f1d6b
commit
00373de886
1 changed files with 199 additions and 84 deletions
283
onepush.sh
283
onepush.sh
|
@ -1,13 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
# ==============================================================================
|
||||
# Automated Open WebUI Installer for Debian (v8 - Robust Cron Job)
|
||||
# Automated Open WebUI & SearXNG Installer (v12 - GPG-Powered)
|
||||
#
|
||||
# This script will:
|
||||
# 1. Use a robust /etc/cron.d file for the scheduled reboot, fixing a script hang.
|
||||
# 2. Detect if UFW is active and handle it decisively.
|
||||
# 3. Install all dependencies and deploy the full stack.
|
||||
# 4. Configure all automations (updates, reboots, security).
|
||||
# 1. Use `gpg` for random data generation, removing the `openssl` dependency.
|
||||
# 2. Correctly configure Nginx to resolve Docker container names.
|
||||
# 3. Deploy a complete, secure, and automated stack for Open WebUI and SearXNG.
|
||||
# ==============================================================================
|
||||
|
||||
# --- Safety Checks ---
|
||||
|
@ -15,7 +14,7 @@ set -euo pipefail
|
|||
|
||||
# --- Pre-flight Checks ---
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
echo "❌ This script must be run as root. Please use 'sudo ./setup-webui.sh'"
|
||||
echo "❌ This script must be run as root. Please use 'sudo ./onepush.sh'"
|
||||
exit 1
|
||||
fi
|
||||
if ! grep -qi "debian" /etc/os-release; then
|
||||
|
@ -24,17 +23,16 @@ fi
|
|||
|
||||
# --- User Input ---
|
||||
echo "---"
|
||||
echo "Welcome to the Automated Open WebUI Installer."
|
||||
echo "Please provide the following information:"
|
||||
echo "Welcome to the Full Stack Open WebUI & SearXNG Installer."
|
||||
echo "---"
|
||||
|
||||
read -p "Enter your domain or subdomain (e.g., webui.example.com): " DOMAIN
|
||||
if [[ -z "$DOMAIN" ]]; then echo "❌ Domain name cannot be empty."; exit 1; fi
|
||||
echo "--- Part 1: Open WebUI Configuration ---"
|
||||
read -p "Enter your domain for Open WebUI (e.g., ai.example.com): " UI_DOMAIN
|
||||
if [[ -z "$UI_DOMAIN" ]]; then echo "❌ Domain name cannot be empty."; exit 1; fi
|
||||
|
||||
read -p "Enter your email address (for Let's Encrypt): " EMAIL
|
||||
if [[ -z "$EMAIL" ]]; then echo "❌ Email address cannot be empty."; exit 1; fi
|
||||
|
||||
read -p "Also secure the 'www' version of this domain (www.$DOMAIN)? [y/N]: " INCLUDE_WWW
|
||||
read -p "Also secure the 'www' version of this domain (www.$UI_DOMAIN)? [y/N]: " UI_INCLUDE_WWW
|
||||
read -p "Use Let's Encrypt staging environment (for testing)? [y/N]: " USE_STAGING
|
||||
|
||||
echo ""
|
||||
|
@ -45,69 +43,103 @@ else
|
|||
read -p "Install and configure UFW firewall? (Recommended) [Y/n]: " MANAGE_UFW
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--- Part 2: Optional SearXNG Search Engine ---"
|
||||
read -p "Deploy a private SearXNG instance for the research tool? [y/N]: " DEPLOY_SEARXNG
|
||||
|
||||
BRAVE_API_KEY=""
|
||||
RESEARCH_TOOL_URL=""
|
||||
if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
|
||||
SEARCH_DOMAIN="search.r21.io"
|
||||
echo "ℹ️ SearXNG will be deployed to https://$SEARCH_DOMAIN"
|
||||
echo "You can provide a Brave Search API key for enhanced, ad-free results."
|
||||
read -p "Enter your Brave Search API key (or press Enter to skip): " BRAVE_API_KEY
|
||||
|
||||
if [[ -z "$BRAVE_API_KEY" ]]; then
|
||||
echo ""
|
||||
echo "You can provide a URL to a custom research_tool.py file."
|
||||
read -p "Enter URL for a custom research_tool.py (or press Enter for default): " RESEARCH_TOOL_URL
|
||||
if [[ -n "$RESEARCH_TOOL_URL" ]]; then
|
||||
echo "Validating URL..."
|
||||
if ! curl --head --fail -sL "$RESEARCH_TOOL_URL" > /dev/null || [[ ! "$RESEARCH_TOOL_URL" == *.py ]]; then
|
||||
echo "❌ Invalid or unreachable URL, or it doesn't end in .py. Proceeding with default."
|
||||
RESEARCH_TOOL_URL=""
|
||||
else
|
||||
echo "✅ URL is valid."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "---"
|
||||
echo "✅ Thank you. Starting the setup for https://$DOMAIN"
|
||||
echo "This process will take several minutes. Please do not interrupt it."
|
||||
echo "✅ Thank you. Starting the setup."
|
||||
sleep 3
|
||||
|
||||
# --- Configuration Variables ---
|
||||
CONTAINER_NAME="open-webui"
|
||||
DATA_VOLUME="open-webui"
|
||||
NGINX_CONF_PATH="/etc/nginx/sites-available/$DOMAIN"
|
||||
NGINX_LOG_PATH="/var/log/nginx/$DOMAIN.access.log"
|
||||
UI_CONTAINER="open-webui"
|
||||
UI_VOLUME="open-webui"
|
||||
NGINX_UI_CONF="/etc/nginx/sites-available/$UI_DOMAIN"
|
||||
NGINX_UI_LOG="/var/log/nginx/$UI_DOMAIN.access.log"
|
||||
|
||||
# --- Step 1: System Preparation and Dependencies ---
|
||||
echo "▶️ [1/9] Updating system and installing dependencies..."
|
||||
echo "▶️ [1/11] Updating system and installing dependencies..."
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -y ca-certificates curl gnupg nginx certbot python3-certbot-nginx fail2ban unattended-upgrades
|
||||
|
||||
# --- Step 2: Configure Firewall (Decisive Handling) ---
|
||||
if [[ "${MANAGE_UFW,,}" != "n" ]]; then
|
||||
echo "▶️ [2/9] Managing Firewall (UFW)..."
|
||||
if ! command -v ufw &> /dev/null; then apt-get install -y ufw; fi
|
||||
ufw allow ssh > /dev/null
|
||||
ufw allow 'Nginx Full' > /dev/null
|
||||
ufw --force enable
|
||||
# MODIFIED: Removed 'openssl' from the dependency list. 'gnupg' is already installed.
|
||||
BASE_PACKAGES="ca-certificates curl gnupg nginx certbot python3-certbot-nginx fail2ban unattended-upgrades"
|
||||
if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
|
||||
apt-get install -y $BASE_PACKAGES apache2-utils
|
||||
else
|
||||
apt-get install -y $BASE_PACKAGES
|
||||
fi
|
||||
|
||||
# --- Step 2: Configure Firewall ---
|
||||
echo "▶️ [2/11] Managing Firewall..."
|
||||
if [[ "${MANAGE_UFW,,}" != "n" ]]; then
|
||||
if ! command -v ufw &> /dev/null; then apt-get install -y ufw; fi
|
||||
ufw allow ssh > /dev/null; ufw allow 'Nginx Full' > /dev/null; ufw --force enable
|
||||
else
|
||||
echo "▶️ [2/9] Skipping firewall rule management as requested."
|
||||
if command -v ufw &> /dev/null && ufw status | grep -q "Status: active"; then
|
||||
echo " - ⚠️ UFW is active but not managed by this script. Disabling it now to prevent cert issuance failure."
|
||||
echo " - ⚠️ UFW is active but not managed. Disabling to prevent setup failure."
|
||||
ufw disable
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Step 3: Install Docker ---
|
||||
echo "▶️ [3/9] Installing Docker..."
|
||||
echo "▶️ [3/11] Installing Docker..."
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
echo \
|
||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
|
||||
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
|
||||
tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
apt-get update
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
|
||||
# --- Step 4: Run Open WebUI Container ---
|
||||
echo "▶️ [4/9] Deploying Open WebUI container..."
|
||||
if [ "$(docker ps -q -f name=$CONTAINER_NAME)" ]; then docker stop $CONTAINER_NAME > /dev/null; fi
|
||||
if [ "$(docker ps -aq -f status=exited -f name=$CONTAINER_NAME)" ]; then docker rm $CONTAINER_NAME > /dev/null; fi
|
||||
# --- Step 4: Create Shared Docker Network ---
|
||||
echo "▶️ [4/11] Setting up Docker network..."
|
||||
if ! docker network ls | grep -q "open-webui-net"; then
|
||||
docker network create open-webui-net
|
||||
fi
|
||||
|
||||
# --- Step 5: Deploy Open WebUI Container ---
|
||||
echo "▶️ [5/11] Deploying Open WebUI container..."
|
||||
docker stop $UI_CONTAINER 2>/dev/null || true
|
||||
docker rm $UI_CONTAINER 2>/dev/null || true
|
||||
docker run -d -p 127.0.0.1:3000:8080 \
|
||||
--add-host=host.docker.internal:host-gateway \
|
||||
-v $DATA_VOLUME:/app/backend/data \
|
||||
--name $CONTAINER_NAME \
|
||||
-v $UI_VOLUME:/app/backend/data \
|
||||
--name $UI_CONTAINER \
|
||||
--network open-webui-net \
|
||||
--restart always \
|
||||
ghcr.io/open-webui/open-webui:main
|
||||
|
||||
# --- Step 5: Configure Nginx Reverse Proxy ---
|
||||
echo "▶️ [5/9] Configuring Nginx..."
|
||||
if [[ "${INCLUDE_WWW,,}" == "y" ]]; then NGINX_SERVER_NAME="$DOMAIN www.$DOMAIN"; else NGINX_SERVER_NAME="$DOMAIN"; fi
|
||||
cat <<EOF > "$NGINX_CONF_PATH"
|
||||
# --- Step 6: Configure Nginx for Open WebUI ---
|
||||
echo "▶️ [6/11] Configuring Nginx for Open WebUI..."
|
||||
if [[ "${UI_INCLUDE_WWW,,}" == "y" ]]; then NGINX_UI_SERVER_NAME="$UI_DOMAIN www.$UI_DOMAIN"; else NGINX_UI_SERVER_NAME="$UI_DOMAIN"; fi
|
||||
cat <<EOF > "$NGINX_UI_CONF"
|
||||
server {
|
||||
listen 80; listen [::]:80;
|
||||
server_name $NGINX_SERVER_NAME;
|
||||
access_log $NGINX_LOG_PATH; error_log /var/log/nginx/$DOMAIN.error.log;
|
||||
server_name $NGINX_UI_SERVER_NAME;
|
||||
access_log $NGINX_UI_LOG; error_log /var/log/nginx/$UI_DOMAIN.error.log;
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr;
|
||||
|
@ -116,21 +148,100 @@ server {
|
|||
}
|
||||
}
|
||||
EOF
|
||||
ln -sfn "$NGINX_CONF_PATH" "/etc/nginx/sites-enabled/$DOMAIN"
|
||||
nginx -t && systemctl reload nginx
|
||||
ln -sfn "$NGINX_UI_CONF" "/etc/nginx/sites-enabled/$UI_DOMAIN"
|
||||
|
||||
# --- Step 6: Obtain SSL Certificate ---
|
||||
echo "▶️ [6/9] Obtaining SSL certificate with Certbot..."
|
||||
if [[ "${INCLUDE_WWW,,}" == "y" ]]; then CERTBOT_DOMAINS="-d $DOMAIN -d www.$DOMAIN"; else CERTBOT_DOMAINS="-d $DOMAIN"; fi
|
||||
CERTBOT_STAGING_FLAG=""
|
||||
if [[ "${USE_STAGING,,}" == "y" ]]; then
|
||||
echo " - Using Let's Encrypt STAGING environment for testing."
|
||||
CERTBOT_STAGING_FLAG="--staging"
|
||||
# --- Step 7: Deploy SearXNG (Optional) ---
|
||||
if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
|
||||
echo "▶️ [7/11] Deploying SearXNG..."
|
||||
|
||||
sudo mkdir -p /srv/searxng
|
||||
|
||||
SECRET_KEY=$(gpg --gen-random --armor 1 24)
|
||||
|
||||
# Dynamically create settings.yml
|
||||
{
|
||||
echo "server:"
|
||||
echo " https: false"
|
||||
echo " secret_key: \"$SECRET_KEY\""
|
||||
echo ""
|
||||
echo "search:"
|
||||
echo " default_lang: en"
|
||||
echo ""
|
||||
echo "engines:"
|
||||
if [[ -n "$BRAVE_API_KEY" ]]; then
|
||||
# MODIFIED: Changed engine name from "brave_search" to "brave"
|
||||
echo " - name: brave"
|
||||
echo " engine: brave"
|
||||
echo " api_key: \"$BRAVE_API_KEY\""
|
||||
echo " shortcut: b"
|
||||
echo " disabled: false"
|
||||
fi
|
||||
certbot --nginx $CERTBOT_DOMAINS $CERTBOT_STAGING_FLAG --non-interactive --agree-tos -m "$EMAIL" --redirect
|
||||
echo " - name: google"
|
||||
echo " engine: google"
|
||||
echo " disabled: false"
|
||||
} | sudo tee /srv/searxng/settings.yml > /dev/null
|
||||
|
||||
# --- Step 7: Configure Security Automations ---
|
||||
echo "▶️ [7/9] Configuring Fail2Ban and automatic system updates..."
|
||||
SEARXNG_CONTAINER="searxng"
|
||||
docker stop $SEARXNG_CONTAINER 2>/dev/null || true
|
||||
docker rm $SEARXNG_CONTAINER 2>/dev/null || true
|
||||
docker run -d \
|
||||
--name $SEARXNG_CONTAINER \
|
||||
--network open-webui-net \
|
||||
-v /srv/searxng:/etc/searxng \
|
||||
--restart always \
|
||||
searxng/searxng
|
||||
else
|
||||
echo "▶️ [7/11] Skipping SearXNG deployment."
|
||||
fi
|
||||
|
||||
# --- Step 8: Configure Nginx for SearXNG (Optional) ---
|
||||
if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
|
||||
echo "▶️ [8/11] Configuring Nginx for SearXNG..."
|
||||
NGINX_SEARCH_CONF="/etc/nginx/sites-available/$SEARCH_DOMAIN"
|
||||
|
||||
echo "Please set a password for the public SearXNG instance."
|
||||
sudo htpasswd -c /etc/nginx/.htpasswd admin
|
||||
|
||||
cat <<EOF > "$NGINX_SEARCH_CONF"
|
||||
server {
|
||||
listen 80; listen [::]:80;
|
||||
server_name $SEARCH_DOMAIN;
|
||||
location / {
|
||||
resolver 127.0.0.11;
|
||||
set \$searxng_upstream http://searxng:8080;
|
||||
proxy_pass \$searxng_upstream;
|
||||
auth_basic "Private Search Instance";
|
||||
auth_basic_user_file /etc/nginx/.htpasswd;
|
||||
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_set_header X-Forwarded-Host \$server_name;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ln -sfn "$NGINX_SEARCH_CONF" "/etc/nginx/sites-enabled/$SEARCH_DOMAIN"
|
||||
else
|
||||
echo "▶️ [8/11] Skipping Nginx config for SearXNG."
|
||||
fi
|
||||
|
||||
# --- Step 9: Obtain SSL Certificates ---
|
||||
echo "▶️ [9/11] Finalizing Nginx and obtaining SSL certificates..."
|
||||
nginx -t
|
||||
CERTBOT_STAGING_FLAG=""
|
||||
if [[ "${USE_STAGING,,}" == "y" ]]; then CERTBOT_STAGING_FLAG="--staging"; fi
|
||||
|
||||
# Get cert for UI Domain
|
||||
if [[ "${UI_INCLUDE_WWW,,}" == "y" ]]; then UI_DOMAINS="-d $UI_DOMAIN -d www.$UI_DOMAIN"; else UI_DOMAINS="-d $UI_DOMAIN"; fi
|
||||
certbot --nginx $UI_DOMAINS $CERTBOT_STAGING_FLAG --non-interactive --agree-tos -m "$EMAIL" --redirect
|
||||
|
||||
# Get cert for Search Domain if deployed
|
||||
if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
|
||||
certbot --nginx -d $SEARCH_DOMAIN $CERTBOT_STAGING_FLAG --non-interactive --agree-tos -m "$EMAIL" --redirect
|
||||
fi
|
||||
|
||||
# --- Step 10: Configure Automations ---
|
||||
echo "▶️ [10/11] Configuring system and service automations..."
|
||||
cat <<EOF > /etc/fail2ban/filter.d/open-webui.conf
|
||||
[Definition]
|
||||
failregex = ^<HOST> .* "POST /api/v1/auths/signin.*" 400
|
||||
|
@ -139,42 +250,46 @@ EOF
|
|||
cat <<EOF > /etc/fail2ban/jail.d/open-webui.local
|
||||
[open-webui]
|
||||
enabled = true; port = http,https; filter = open-webui;
|
||||
logpath = $NGINX_LOG_PATH; maxretry = 5; findtime = 3600; bantime = 86400;
|
||||
logpath = $NGINX_UI_LOG; maxretry = 5; findtime = 3600; bantime = 86400;
|
||||
EOF
|
||||
systemctl restart fail2ban
|
||||
dpkg-reconfigure -plow unattended-upgrades
|
||||
|
||||
# --- Step 8: Configure Service Automations ---
|
||||
echo "▶️ [8/9] Deploying Watchtower and scheduling reboots..."
|
||||
if ! [ "$(docker ps -q -f name=watchtower)" ]; then
|
||||
docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock --restart always containrrr/watchtower
|
||||
fi
|
||||
echo "0 9 * * 5 root /sbin/reboot # Weekly reboot for system health" > /etc/cron.d/weekly-reboot
|
||||
|
||||
# MODIFIED: Using a robust cron drop-in file instead of piping to crontab.
|
||||
echo " - Scheduling weekly reboot for Friday at 09:00 UTC..."
|
||||
echo "0 9 * * 5 root /sbin/reboot # Weekly reboot for system health" > /etc/cron.d/open-webui-reboot
|
||||
|
||||
# --- Step 9: Finalization ---
|
||||
echo "▶️ [9/9] Finalizing and cleaning up..."
|
||||
# --- Step 11: Finalization ---
|
||||
echo "▶️ [11/11] Finalizing..."
|
||||
systemctl restart nginx
|
||||
systemctl restart fail2ban
|
||||
|
||||
echo ""
|
||||
echo "---"
|
||||
echo "✅🎉 **DEPLOYMENT COMPLETE!** 🎉✅"
|
||||
echo ""
|
||||
echo "Open WebUI is now running and accessible at: https://$DOMAIN"
|
||||
echo ""
|
||||
echo "IMPORTANT NOTES:"
|
||||
if [[ "${MANAGE_UFW,,}" == "n" ]]; then
|
||||
echo " - ⚠️ UFW was detected and has been DISABLED to allow this script to complete."
|
||||
echo " Your server's firewall is currently off. You are responsible for its configuration."
|
||||
echo "--- ACCESS ---"
|
||||
echo " - Open WebUI: https://$UI_DOMAIN"
|
||||
if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
|
||||
echo " - SearXNG: https://$SEARCH_DOMAIN (user: admin)"
|
||||
fi
|
||||
if [[ "${USE_STAGING,,}" == "y" ]]; then
|
||||
echo " - ⚠️ You used a STAGING certificate. Your site will show a browser security warning."
|
||||
echo " To fix this, re-run this script after your rate limit expires and choose 'N' for staging."
|
||||
fi
|
||||
echo " - The Fail2Ban rule is active and will protect your login endpoint."
|
||||
echo " - The first user to sign up will become the administrator."
|
||||
echo " - Your system and the WebUI container will update automatically."
|
||||
echo " - The server will reboot every Friday at 09:00 UTC."
|
||||
echo ""
|
||||
echo "--- NEXT STEPS: ADDING THE RESEARCH TOOL ---"
|
||||
if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
|
||||
echo "1. Go to Open WebUI -> Settings -> Tools."
|
||||
echo "2. Click 'Add Tool' and paste the Python code below into the editor."
|
||||
echo "3. Open the 'Settings' tab in the tool editor."
|
||||
echo "4. In the 'Environment Variables' section, add:"
|
||||
echo " - Key: SEARXNG_BASE_URL"
|
||||
echo " - Value: http://searxng:8080"
|
||||
echo "5. Click 'Save' to finish."
|
||||
echo ""
|
||||
echo "--- Python Code for Research Tool ---"
|
||||
if [[ -n "$RESEARCH_TOOL_URL" ]]; then
|
||||
echo "Paste the content from your custom URL: $RESEARCH_TOOL_URL"
|
||||
else
|
||||
echo "Paste the default code from here: https://github.com/iamarcel/open-webui-utils/blob/main/research_tool.py"
|
||||
fi
|
||||
else
|
||||
echo "SearXNG was not deployed, so no research tool was configured."
|
||||
fi
|
||||
echo "---"
|
Loading…
Add table
Add a link
Reference in a new issue