diff --git a/onepush.sh b/onepush.sh index 058b9dc..b8b095e 100644 --- a/onepush.sh +++ b/onepush.sh @@ -1,42 +1,29 @@ #!/bin/bash # ============================================================================== -# Automated Open WebUI Installer for Debian (v8 - Robust Cron Job) +# Automated Open WebUI & SearXNG Installer (v19 - The Definitive) # # 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 the user's superior method of `curl` to fetch the default SearXNG config. +# 2. Surgically inject the Brave API key into the downloaded config. +# 3. Deploy a complete, secure, and automated stack for Open WebUI and SearXNG. # ============================================================================== # --- Safety Checks --- 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'" - 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 +if [[ "$EUID" -ne 0 ]]; then echo "❌ This script must be run as root."; exit 1; fi +if ! grep -qi "debian" /etc/os-release; then echo "⚠️ This script is optimized for Debian."; 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 - +read -p "Enter your domain for Open WebUI (e.g., ai.example.com): " UI_DOMAIN 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 "" if command -v ufw &> /dev/null; then echo "ℹ️ UFW firewall is detected on this system." @@ -44,70 +31,100 @@ if command -v ufw &> /dev/null; then else read -p "Install and configure UFW firewall? (Recommended) [Y/n]: " MANAGE_UFW 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 "---" -echo "✅ Thank you. Starting the setup for https://$DOMAIN" -echo "This process will take several minutes. Please do not interrupt it." -sleep 3 +# --- Main Script --- +echo "---"; 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" +# --- Configuration --- +UI_CONTAINER="open-webui" +SEARXNG_CONTAINER="searxng" +NETWORK_NAME="open-webui-net" +SEARXNG_CONFIG_DIR="/srv/searxng" -# --- Step 1: System Preparation and Dependencies --- -echo "▶️ [1/9] Updating system and installing dependencies..." +# --- Step 1: Dependencies --- +echo "▶️ [1/9] 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 +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 (Decisive Handling) --- +# --- Step 2: Firewall Management --- +echo "▶️ [2/9] Managing Firewall..." 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 + 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..." +# --- Step 3: Docker & Network --- +echo "▶️ [3/9] Installing Docker and setting up network..." 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 +if ! docker network ls | grep -q "$NETWORK_NAME"; then docker network create $NETWORK_NAME; fi -# --- 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 -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 4: Stop Old Containers --- +echo "▶️ [4/9] Stopping and removing any old containers..." +docker stop $UI_CONTAINER $SEARXNG_CONTAINER 2>/dev/null || true +docker rm $UI_CONTAINER $SEARXNG_CONTAINER 2>/dev/null || true -# --- 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 < "$NGINX_CONF_PATH" +# --- Step 5: Configure and Deploy SearXNG (Optional) --- +if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then + echo "▶️ [5/9] Configuring and deploying SearXNG..." + + # 1. Fetch the default settings.yml directly from GitHub + echo " - Fetching default SearXNG configuration from GitHub..." + sudo mkdir -p $SEARXNG_CONFIG_DIR + sudo curl -sL "https://raw.githubusercontent.com/searxng/searxng/master/searx/settings.yml" -o "$SEARXNG_CONFIG_DIR/settings.yml" + + # 2. Surgically inject the Brave API key if provided + if [[ -n "$BRAVE_API_KEY" ]]; then + echo " - Injecting Brave API key..." + sudo sed -i "/^- name: brave/a \ api_key: \"$BRAVE_API_KEY\"" "$SEARXNG_CONFIG_DIR/settings.yml" + else + echo " - No Brave API key provided, using default settings." + fi + + # 3. Add a mandatory secret_key + SECRET_KEY=$(gpg --gen-random --armor 1 24) + sudo sed -i "s/ultrasecretkey/\"$SECRET_KEY\"/" "$SEARXNG_CONFIG_DIR/settings.yml" + + # 4. Set correct permissions + sudo chown -R 1000:1000 $SEARXNG_CONFIG_DIR + + # 5. Launch the final container + echo " - Starting SearXNG container..." + docker run -d --name $SEARXNG_CONTAINER --network $NETWORK_NAME -v $SEARXNG_CONFIG_DIR:/etc/searxng --restart always searxng/searxng +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 < "$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; + listen 80; listen [::]:80; server_name $UI_SERVER_NAME; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; @@ -116,21 +133,42 @@ 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" +if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then + 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 < "$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" fi -certbot --nginx $CERTBOT_DOMAINS $CERTBOT_STAGING_FLAG --non-interactive --agree-tos -m "$EMAIL" --redirect -# --- Step 7: Configure Security Automations --- -echo "▶️ [7/9] Configuring Fail2Ban and automatic system updates..." +# --- Step 8: SSL Certificates & Automations --- +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 < /etc/fail2ban/filter.d/open-webui.conf [Definition] failregex = ^ .* "POST /api/v1/auths/signin.*" 400 @@ -139,42 +177,30 @@ EOF cat < /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 - -# 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 +echo "0 9 * * 5 root /sbin/reboot" > /etc/cron.d/weekly-reboot # --- Step 9: Finalization --- -echo "▶️ [9/9] Finalizing and cleaning up..." +echo "▶️ [9/9] Finalizing..." 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 "✅🎉 **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 "--- NEXT STEPS: ADDING THE RESEARCH TOOL ---" +if [[ "${DEPLOY_SEARXNG,,}" == "y" ]]; then + echo "1. Go to Open WebUI -> Settings -> Tools." + echo "2. Paste the Python code from https://github.com/iamarcel/open-webui-utils/blob/main/research_tool.py" + echo "3. Go to the Settings tab in the tool editor." + echo "4. Add Environment Variable: Key: SEARXNG_BASE_URL, Value: http://searxng:8080" + echo "5. Click 'Save'." 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 "" \ No newline at end of file +echo "---" \ No newline at end of file