Compare commits

..

3 commits

Author SHA1 Message Date
dd95fa27b2 working searxng 2025-07-11 18:08:55 +00:00
816fc7e7ab progress 2025-07-11 06:53:44 +00:00
00373de886 Update onepush.sh 2025-07-11 06:15:12 +00:00

View file

@ -1,42 +1,34 @@
#!/bin/bash #!/bin/bash
# ============================================================================== # ==============================================================================
# Automated Open WebUI Installer for Debian (v8 - Robust Cron Job) # Automated Open WebUI & SearXNG Installer (v26 - The Definitive Version)
# #
# This script will: # This script is the final, consolidated version incorporating all bug fixes
# 1. Use a robust /etc/cron.d file for the scheduled reboot, fixing a script hang. # and best practices discovered through our collaborative debugging process.
# 2. Detect if UFW is active and handle it decisively. #
# 3. Install all dependencies and deploy the full stack. # Key Fixes:
# 4. Configure all automations (updates, reboots, security). # 1. Uses a robust "port-publishing" method for Nginx-to-Docker communication.
# 2. Uses environment variables to configure SearXNG, the correct method.
# 3. Uses a safe, non-blocking command to generate secrets.
# 4. Builds Docker commands safely in an array to prevent errors.
# 5. All previous logic (UFW, cron, etc.) is complete and verified.
# ============================================================================== # ==============================================================================
# --- Safety Checks --- # --- Safety Checks ---
set -euo pipefail set -euo pipefail
# --- Pre-flight Checks --- # --- Pre-flight Checks ---
if [[ "$EUID" -ne 0 ]]; then if [[ "$EUID" -ne 0 ]]; then echo "❌ This script must be run as root."; exit 1; fi
echo "❌ This script must be run as root. Please use 'sudo ./setup-webui.sh'" if ! grep -qi "debian" /etc/os-release; then echo "⚠️ This script is optimized for Debian."; fi
exit 1
fi
if ! grep -qi "debian" /etc/os-release; then
echo "⚠️ This script is optimized for Debian. Running on another OS may have unintended results."
fi
# --- User Input --- # --- User Input ---
echo "---" echo "---"
echo "Welcome to the Automated Open WebUI Installer." echo "Welcome to the Full Stack Open WebUI & SearXNG Installer."
echo "Please provide the following information:"
echo "---" echo "---"
read -p "Enter your domain for Open WebUI (e.g., ai.example.com): " UI_DOMAIN
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
read -p "Enter your email address (for Let's Encrypt): " EMAIL 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.$UI_DOMAIN)? [y/N]: " UI_INCLUDE_WWW
read -p "Also secure the 'www' version of this domain (www.$DOMAIN)? [y/N]: " INCLUDE_WWW
read -p "Use Let's Encrypt staging environment (for testing)? [y/N]: " USE_STAGING read -p "Use Let's Encrypt staging environment (for testing)? [y/N]: " USE_STAGING
echo "" echo ""
if command -v ufw &> /dev/null; then if command -v ufw &> /dev/null; then
echo " UFW firewall is detected on this system." echo " UFW firewall is detected on this system."
@ -44,70 +36,113 @@ if command -v ufw &> /dev/null; then
else else
read -p "Install and configure UFW firewall? (Recommended) [Y/n]: " MANAGE_UFW read -p "Install and configure UFW firewall? (Recommended) [Y/n]: " MANAGE_UFW
fi fi
echo ""
read -p "Deploy a private SearXNG instance for the research tool? [y/N]: " DEPLOY_SEARXNG
BRAVE_API_KEY=""
if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
SEARCH_DOMAIN="search.r21.io"
echo " SearXNG will be deployed to https://$SEARCH_DOMAIN"
read -p "Enter your Brave Search API key (highly recommended, or press Enter): " BRAVE_API_KEY
fi
echo "---" # --- Main Script ---
echo "✅ Thank you. Starting the setup for https://$DOMAIN" echo "---"; echo "✅ Thank you. Starting the setup."; sleep 3
echo "This process will take several minutes. Please do not interrupt it."
sleep 3
# --- Configuration Variables --- # --- Configuration ---
CONTAINER_NAME="open-webui" UI_CONTAINER="open-webui"
DATA_VOLUME="open-webui" SEARXNG_CONTAINER="searxng"
NGINX_CONF_PATH="/etc/nginx/sites-available/$DOMAIN" NETWORK_NAME="open-webui-net"
NGINX_LOG_PATH="/var/log/nginx/$DOMAIN.access.log"
# --- Step 1: System Preparation and Dependencies --- # --- Step 1: Dependencies ---
echo "▶️ [1/9] Updating system and installing dependencies..." echo "▶️ [1/9] Installing dependencies..."
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
apt-get update apt-get update
apt-get install -y ca-certificates curl gnupg nginx certbot python3-certbot-nginx fail2ban unattended-upgrades # Add openssl for robust secret generation
BASE_PACKAGES="ca-certificates curl gnupg nginx certbot python3-certbot-nginx fail2ban unattended-upgrades openssl"
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 (Decisive Handling) --- # --- Step 2: Firewall Management ---
echo "▶️ [2/9] Managing Firewall..."
if [[ -z "${MANAGE_UFW+x}" ]]; then MANAGE_UFW="y"; fi
if [[ "${MANAGE_UFW,,}" != "n" ]]; then if [[ "${MANAGE_UFW,,}" != "n" ]]; then
echo "▶️ [2/9] Managing Firewall (UFW)..."
if ! command -v ufw &> /dev/null; then apt-get install -y ufw; fi if ! command -v ufw &> /dev/null; then apt-get install -y ufw; fi
ufw allow ssh > /dev/null ufw allow ssh > /dev/null; ufw allow 'Nginx Full' > /dev/null; ufw --force enable
ufw allow 'Nginx Full' > /dev/null
ufw --force enable
else else
echo "▶️ [2/9] Skipping firewall rule management as requested."
if command -v ufw &> /dev/null && ufw status | grep -q "Status: active"; then 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 ufw disable
fi fi
fi fi
# --- Step 3: Install Docker --- # --- Step 3: Docker & Network ---
echo "▶️ [3/9] Installing Docker..." echo "▶️ [3/9] Installing Docker and setting up network..."
install -m 0755 -d /etc/apt/keyrings install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg 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 chmod a+r /etc/apt/keyrings/docker.gpg
echo \ 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
"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 update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
if ! docker network ls | grep -q "$NETWORK_NAME"; then docker network create $NETWORK_NAME; fi
# --- Step 4: Run Open WebUI Container --- # --- Step 4: Stop Old Containers ---
echo "▶️ [4/9] Deploying Open WebUI container..." echo "▶️ [4/9] Stopping and removing any old containers..."
if [ "$(docker ps -q -f name=$CONTAINER_NAME)" ]; then docker stop $CONTAINER_NAME > /dev/null; fi docker stop $UI_CONTAINER $SEARXNG_CONTAINER 2>/dev/null || true
if [ "$(docker ps -aq -f status=exited -f name=$CONTAINER_NAME)" ]; then docker rm $CONTAINER_NAME > /dev/null; fi docker rm $UI_CONTAINER $SEARXNG_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 \
--restart always \
ghcr.io/open-webui/open-webui:main
# --- Step 5: Configure Nginx Reverse Proxy --- # --- Step 5: Configure and Deploy SearXNG (Optional) ---
echo "▶️ [5/9] Configuring Nginx..." if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
if [[ "${INCLUDE_WWW,,}" == "y" ]]; then NGINX_SERVER_NAME="$DOMAIN www.$DOMAIN"; else NGINX_SERVER_NAME="$DOMAIN"; fi echo "▶️ [5/9] Deploying SearXNG..."
cat <<EOF > "$NGINX_CONF_PATH"
# Generate a robust, shell-safe secret key
SECRET_KEY=$(openssl rand -hex 32)
# Build the docker run command safely in an array
docker_cmd=(
docker run -d
--name "$SEARXNG_CONTAINER"
--network "$NETWORK_NAME"
# Publish port to localhost for Nginx to connect to
-p "127.0.0.1:8081:8080"
# Core settings via environment variables
-e "SEARXNG_SECRET=$SECRET_KEY"
-e "SEARXNG_BIND_ADDRESS=0.0.0.0" # Listen on all interfaces inside the container
-e "SEARXNG_BASE_URL=https://$SEARCH_DOMAIN"
--restart always
)
# Add optional Brave integration
if [[ -n "$BRAVE_API_KEY" ]]; then
echo " - Enabling Brave engine with API key..."
docker_cmd+=(
-e "SEARXNG_ENGINES_BRAVE_API_KEY=$BRAVE_API_KEY"
-e "SEARXNG_ENGINES_BRAVE_DISABLED=false"
# Disable a noisy engine if a key is present
-e "SEARXNG_ENGINES_DUCKDUCKGO_DISABLED=true"
)
else
echo " - No Brave API key provided, using default search engines."
fi
# Add the image name to the end of the command
docker_cmd+=(searxng/searxng)
# Execute the final, safe command
"${docker_cmd[@]}"
else
echo "▶️ [5/9] Skipping SearXNG deployment."
fi
# --- Step 6: Deploy Open WebUI ---
echo "▶️ [6/9] Deploying Open WebUI..."
docker run -d -p 127.0.0.1:3000:8080 -v open-webui:/app/backend/data --name $UI_CONTAINER --network $NETWORK_NAME --restart always ghcr.io/open-webui/open-webui:main
# --- Step 7: Configure Nginx ---
echo "▶️ [7/9] Configuring Nginx sites..."
NGINX_UI_CONF="/etc/nginx/sites-available/$UI_DOMAIN"
if [[ "${UI_INCLUDE_WWW,,}" == "y" ]]; then UI_SERVER_NAME="$UI_DOMAIN www.$UI_DOMAIN"; else UI_SERVER_NAME="$UI_DOMAIN"; fi
cat <<EOF > "$NGINX_UI_CONF"
server { server {
listen 80; listen [::]:80; listen 80; listen [::]:80; server_name $UI_SERVER_NAME;
server_name $NGINX_SERVER_NAME;
access_log $NGINX_LOG_PATH; error_log /var/log/nginx/$DOMAIN.error.log;
location / { location / {
proxy_pass http://127.0.0.1:3000; proxy_pass http://127.0.0.1:3000;
proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr;
@ -116,21 +151,42 @@ server {
} }
} }
EOF EOF
ln -sfn "$NGINX_CONF_PATH" "/etc/nginx/sites-enabled/$DOMAIN" ln -sfn "$NGINX_UI_CONF" "/etc/nginx/sites-enabled/$UI_DOMAIN"
nginx -t && systemctl reload nginx
# --- Step 6: Obtain SSL Certificate --- if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
echo "▶️ [6/9] Obtaining SSL certificate with Certbot..." NGINX_SEARCH_CONF="/etc/nginx/sites-available/$SEARCH_DOMAIN"
if [[ "${INCLUDE_WWW,,}" == "y" ]]; then CERTBOT_DOMAINS="-d $DOMAIN -d www.$DOMAIN"; else CERTBOT_DOMAINS="-d $DOMAIN"; fi echo "Please set a password for the public SearXNG instance."
CERTBOT_STAGING_FLAG="" sudo htpasswd -c /etc/nginx/.htpasswd admin
if [[ "${USE_STAGING,,}" == "y" ]]; then cat <<EOF > "$NGINX_SEARCH_CONF"
echo " - Using Let's Encrypt STAGING environment for testing." server {
CERTBOT_STAGING_FLAG="--staging" listen 80; listen [::]:80; server_name $SEARCH_DOMAIN;
location / {
# Proxy directly to the port we published on the host's localhost
proxy_pass http://127.0.0.1:8081;
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"
fi fi
certbot --nginx $CERTBOT_DOMAINS $CERTBOT_STAGING_FLAG --non-interactive --agree-tos -m "$EMAIL" --redirect
# --- Step 7: Configure Security Automations --- # --- Step 8: SSL Certificates & Automations ---
echo "▶️ [7/9] Configuring Fail2Ban and automatic system updates..." echo "▶️ [8/9] Obtaining SSL certificates and configuring automations..."
nginx -t
CERTBOT_STAGING_FLAG=""
if [[ "${USE_STAGING,,}" == "y" ]]; then CERTBOT_STAGING_FLAG="--staging"; fi
certbot --nginx -d $UI_SERVER_NAME $CERTBOT_STAGING_FLAG --non-interactive --agree-tos -m "$EMAIL" --redirect
if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
certbot --nginx -d $SEARCH_DOMAIN $CERTBOT_STAGING_FLAG --non-interactive --agree-tos -m "$EMAIL" --redirect
fi
NGINX_UI_LOG="/var/log/nginx/$UI_DOMAIN.access.log"
touch $NGINX_UI_LOG && chown www-data:adm $NGINX_UI_LOG
cat <<EOF > /etc/fail2ban/filter.d/open-webui.conf cat <<EOF > /etc/fail2ban/filter.d/open-webui.conf
[Definition] [Definition]
failregex = ^<HOST> .* "POST /api/v1/auths/signin.*" 400 failregex = ^<HOST> .* "POST /api/v1/auths/signin.*" 400
@ -139,42 +195,30 @@ EOF
cat <<EOF > /etc/fail2ban/jail.d/open-webui.local cat <<EOF > /etc/fail2ban/jail.d/open-webui.local
[open-webui] [open-webui]
enabled = true; port = http,https; filter = 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 EOF
systemctl restart fail2ban systemctl restart fail2ban
dpkg-reconfigure -plow unattended-upgrades 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 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 docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock --restart always containrrr/watchtower
fi fi
echo "0 9 * * 5 root /sbin/reboot" > /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 --- # --- Step 9: Finalization ---
echo "▶️ [9/9] Finalizing and cleaning up..." echo "▶️ [9/9] Finalizing..."
systemctl restart nginx systemctl restart nginx
systemctl restart fail2ban
echo "---"; echo "✅🎉 **DEPLOYMENT COMPLETE!** 🎉✅"; echo ""
echo "--- ACCESS ---"
echo " - Open WebUI: https://$UI_DOMAIN"
if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then echo " - SearXNG: https://$SEARCH_DOMAIN (user: admin)"; fi
echo "" echo ""
echo "✅🎉 **DEPLOYMENT COMPLETE!** 🎉✅" echo "--- NEXT STEPS: ADDING THE RESEARCH TOOL ---"
echo "" if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then
echo "Open WebUI is now running and accessible at: https://$DOMAIN" echo "1. Go to Open WebUI -> Settings -> Tools."
echo "" echo "2. Paste the Python code from https://github.com/iamarcel/open-webui-utils/blob/main/research_tool.py"
echo "IMPORTANT NOTES:" echo "3. Go to the Settings tab in the tool editor."
if [[ "${MANAGE_UFW,,}" == "n" ]]; then echo "4. Add Environment Variable: Key: SEARXNG_BASE_URL, Value: http://searxng:8080"
echo " - ⚠️ UFW was detected and has been DISABLED to allow this script to complete." echo "5. Click 'Save'."
echo " Your server's firewall is currently off. You are responsible for its configuration."
fi fi
if [[ "${USE_STAGING,,}" == "y" ]]; then echo "---"
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 ""