searx.sh 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091
  1. #!/usr/bin/env bash
  2. # SPDX-License-Identifier: AGPL-3.0-or-later
  3. # shellcheck disable=SC2001
  4. # shellcheck source=utils/lib.sh
  5. source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
  6. # shellcheck source=utils/lib_install.sh
  7. source "${REPO_ROOT}/utils/lib_install.sh"
  8. # ----------------------------------------------------------------------------
  9. # config
  10. # ----------------------------------------------------------------------------
  11. SEARX_INTERNAL_HTTP="${SEARXNG_BIND_ADDRESS}:${SEARXNG_PORT}"
  12. SEARXNG_URL_PATH="${SEARXNG_URL_PATH:-$(echo "${PUBLIC_URL}" \
  13. | sed -e 's,^.*://[^/]*\(/.*\),\1,g')}"
  14. [[ "${SEARXNG_URL_PATH}" == "${PUBLIC_URL}" ]] && SEARXNG_URL_PATH=/
  15. SERVICE_NAME="searx"
  16. SERVICE_USER="${SERVICE_USER:-${SERVICE_NAME}}"
  17. SERVICE_HOME_BASE="${SERVICE_HOME_BASE:-/usr/local}"
  18. SERVICE_HOME="${SERVICE_HOME_BASE}/${SERVICE_USER}"
  19. # shellcheck disable=SC2034
  20. SERVICE_GROUP="${SERVICE_USER}"
  21. GIT_BRANCH="${GIT_BRANCH:-master}"
  22. SEARX_PYENV="${SERVICE_HOME}/searx-pyenv"
  23. SEARX_SRC="${SERVICE_HOME}/searx-src"
  24. SEARXNG_SETTINGS_PATH="/etc/searxng/settings.yml"
  25. SEARXNG_UWSGI_APP="searxng.ini"
  26. # shellcheck disable=SC2034
  27. SEARX_UWSGI_SOCKET="/run/uwsgi/app/searx/socket"
  28. # apt packages
  29. SEARX_PACKAGES_debian="\
  30. python3-dev python3-babel python3-venv
  31. uwsgi uwsgi-plugin-python3
  32. git build-essential libxslt-dev zlib1g-dev libffi-dev libssl-dev
  33. shellcheck"
  34. BUILD_PACKAGES_debian="\
  35. firefox graphviz imagemagick texlive-xetex librsvg2-bin
  36. texlive-latex-recommended texlive-extra-utils fonts-dejavu
  37. latexmk
  38. npm"
  39. # pacman packages
  40. SEARX_PACKAGES_arch="\
  41. python python-pip python-lxml python-babel
  42. uwsgi uwsgi-plugin-python
  43. git base-devel libxml2
  44. shellcheck"
  45. BUILD_PACKAGES_arch="\
  46. firefox graphviz imagemagick texlive-bin extra/librsvg
  47. texlive-core texlive-latexextra ttf-dejavu
  48. npm"
  49. # dnf packages
  50. SEARX_PACKAGES_fedora="\
  51. python python-pip python-lxml python-babel
  52. uwsgi uwsgi-plugin-python3
  53. git @development-tools libxml2
  54. ShellCheck"
  55. BUILD_PACKAGES_fedora="\
  56. firefox graphviz graphviz-gd ImageMagick librsvg2-tools
  57. texlive-xetex-bin texlive-collection-fontsrecommended
  58. texlive-collection-latex dejavu-sans-fonts dejavu-serif-fonts
  59. dejavu-sans-mono-fonts
  60. npm"
  61. # yum packages
  62. #
  63. # hint: We do no longer support yum packages, it is to complex to maintain
  64. # automate installation of packages like npm. In the firts step we ignore
  65. # CentOS-7 as developer & build platform (the inital patch which brought
  66. # CentOS-7 supports was not intended to be a developer platform).
  67. SEARX_PACKAGES_centos="\
  68. python36 python36-pip python36-lxml python-babel
  69. uwsgi uwsgi-plugin-python3
  70. git @development-tools libxml2
  71. ShellCheck"
  72. BUILD_PACKAGES_centos="\
  73. firefox graphviz graphviz-gd ImageMagick librsvg2-tools
  74. texlive-xetex-bin texlive-collection-fontsrecommended
  75. texlive-collection-latex dejavu-sans-fonts dejavu-serif-fonts
  76. dejavu-sans-mono-fonts"
  77. case $DIST_ID-$DIST_VERS in
  78. ubuntu-16.04|ubuntu-18.04)
  79. SEARX_PACKAGES="${SEARX_PACKAGES_debian}"
  80. BUILD_PACKAGES="${BUILD_PACKAGES_debian}"
  81. APACHE_PACKAGES="$APACHE_PACKAGES libapache2-mod-proxy-uwsgi"
  82. ;;
  83. ubuntu-20.04)
  84. # https://askubuntu.com/a/1224710
  85. SEARX_PACKAGES="${SEARX_PACKAGES_debian} python-is-python3"
  86. BUILD_PACKAGES="${BUILD_PACKAGES_debian}"
  87. ;;
  88. ubuntu-*|debian-*)
  89. SEARX_PACKAGES="${SEARX_PACKAGES_debian}"
  90. BUILD_PACKAGES="${BUILD_PACKAGES_debian}"
  91. ;;
  92. arch-*)
  93. SEARX_PACKAGES="${SEARX_PACKAGES_arch}"
  94. BUILD_PACKAGES="${BUILD_PACKAGES_arch}"
  95. ;;
  96. fedora-*)
  97. SEARX_PACKAGES="${SEARX_PACKAGES_fedora}"
  98. BUILD_PACKAGES="${BUILD_PACKAGES_fedora}"
  99. ;;
  100. centos-7)
  101. SEARX_PACKAGES="${SEARX_PACKAGES_centos}"
  102. BUILD_PACKAGES="${BUILD_PACKAGES_centos}"
  103. ;;
  104. esac
  105. # Apache Settings
  106. APACHE_SEARX_SITE="searx.conf"
  107. # shellcheck disable=SC2034
  108. CONFIG_FILES=(
  109. "${uWSGI_APPS_AVAILABLE}/${SEARXNG_UWSGI_APP}"
  110. )
  111. # shellcheck disable=SC2034
  112. CONFIG_BACKUP_ENCRYPTED=(
  113. "${SEARXNG_SETTINGS_PATH}"
  114. )
  115. # ----------------------------------------------------------------------------
  116. usage() {
  117. # ----------------------------------------------------------------------------
  118. # shellcheck disable=SC1117
  119. cat <<EOF
  120. usage::
  121. $(basename "$0") shell
  122. $(basename "$0") install [all|check|init-src|dot-config|user|searx-src|pyenv|uwsgi|packages|settings|buildhost]
  123. $(basename "$0") update [searx]
  124. $(basename "$0") remove [all|user|pyenv|searx-src]
  125. $(basename "$0") activate [service]
  126. $(basename "$0") deactivate [service]
  127. $(basename "$0") inspect [service|settings <key>]
  128. $(basename "$0") option [debug-[on|off]|image-proxy-[on|off]|result-proxy <url> <key>]
  129. $(basename "$0") apache [install|remove]
  130. shell
  131. start interactive shell from user ${SERVICE_USER}
  132. install / remove
  133. :all: complete (de-) installation of searx service
  134. :user: add/remove service user '$SERVICE_USER' ($SERVICE_HOME)
  135. :dot-config: copy ./config.sh to ${SEARX_SRC}
  136. :searx-src: clone $GIT_URL
  137. :init-src: copy files (SEARX_SRC_INIT_FILES) to ${SEARX_SRC}
  138. :pyenv: create/remove virtualenv (python) in $SEARX_PYENV
  139. :uwsgi: install searx uWSGI application
  140. :settings: reinstall settings from ${SEARXNG_SETTINGS_PATH}
  141. :packages: install needed packages from OS package manager
  142. :buildhost: install packages from OS package manager needed by buildhosts
  143. install
  144. :check: check the SearXNG installation
  145. update searx
  146. Update SearXNG installation ($SERVICE_HOME)
  147. activate service
  148. activate and start service daemon (systemd unit)
  149. deactivate service
  150. stop and deactivate service daemon (systemd unit)
  151. inspect
  152. :service: run some small tests and inspect service's status and log
  153. :settings: inspect YAML setting <key> from SearXNG instance (${SEARX_SRC})
  154. option
  155. set one of the available options
  156. apache
  157. :install: apache site with the SearXNG uwsgi app
  158. :remove: apache site ${APACHE_FILTRON_SITE}
  159. ---- sourced ${DOT_CONFIG}
  160. SERVICE_USER : ${SERVICE_USER}
  161. SERVICE_HOME : ${SERVICE_HOME}
  162. EOF
  163. install_log_searx_instance
  164. [[ -n ${1} ]] && err_msg "$1"
  165. }
  166. main() {
  167. required_commands \
  168. sudo systemctl install git wget curl \
  169. || exit
  170. local _usage="unknown or missing $1 command $2"
  171. case $1 in
  172. --getenv) var="$2"; echo "${!var}"; exit 0;;
  173. -h|--help) usage; exit 0;;
  174. shell)
  175. sudo_or_exit
  176. interactive_shell "${SERVICE_USER}"
  177. ;;
  178. inspect)
  179. case $2 in
  180. service)
  181. sudo_or_exit
  182. inspect_service
  183. ;;
  184. settings)
  185. prompt_installation_setting "$3"
  186. dump_return $?
  187. ;;
  188. *) usage "$_usage"; exit 42;;
  189. esac ;;
  190. install)
  191. sudo_or_exit
  192. case $2 in
  193. all)
  194. rst_title "SearXNG (install)" part
  195. install_all
  196. ;;
  197. check)
  198. rst_title "SearXNG (check installation)" part
  199. verify_continue_install
  200. install_check
  201. ;;
  202. user)
  203. rst_title "SearXNG (install user)"
  204. verify_continue_install
  205. assert_user
  206. ;;
  207. pyenv)
  208. rst_title "SearXNG (install pyenv)"
  209. verify_continue_install
  210. create_pyenv
  211. ;;
  212. searx-src)
  213. rst_title "SearXNG (install searx-src)"
  214. verify_continue_install
  215. assert_user
  216. clone_searx
  217. install_DOT_CONFIG
  218. init_SEARX_SRC
  219. ;;
  220. init-src)
  221. init_SEARX_SRC
  222. ;;
  223. dot-config)
  224. install_DOT_CONFIG
  225. ;;
  226. settings)
  227. install_settings
  228. ;;
  229. uwsgi)
  230. rst_title "SearXNG (install uwsgi)"
  231. verify_continue_install
  232. install_searx_uwsgi
  233. if ! service_is_available "http://${SEARX_INTERNAL_HTTP}"; then
  234. err_msg "URL http://${SEARX_INTERNAL_HTTP} not available, check SearXNG & uwsgi setup!"
  235. fi
  236. ;;
  237. packages)
  238. rst_title "SearXNG (install packages)"
  239. pkg_install "$SEARX_PACKAGES"
  240. ;;
  241. buildhost)
  242. rst_title "SearXNG (install buildhost)"
  243. pkg_install "$SEARX_PACKAGES"
  244. pkg_install "$BUILD_PACKAGES"
  245. ;;
  246. *) usage "$_usage"; exit 42;;
  247. esac ;;
  248. update)
  249. sudo_or_exit
  250. case $2 in
  251. searx) update_searx;;
  252. *) usage "$_usage"; exit 42;;
  253. esac ;;
  254. remove)
  255. rst_title "SearXNG (remove)" part
  256. sudo_or_exit
  257. case $2 in
  258. all) remove_all;;
  259. user) drop_service_account "${SERVICE_USER}";;
  260. pyenv) remove_pyenv ;;
  261. searx-src) remove_searx ;;
  262. *) usage "$_usage"; exit 42;;
  263. esac ;;
  264. activate)
  265. sudo_or_exit
  266. case $2 in
  267. service)
  268. activate_service ;;
  269. *) usage "$_usage"; exit 42;;
  270. esac ;;
  271. deactivate)
  272. sudo_or_exit
  273. case $2 in
  274. service) deactivate_service ;;
  275. *) usage "$_usage"; exit 42;;
  276. esac ;;
  277. option)
  278. sudo_or_exit
  279. case $2 in
  280. debug-on) echo; enable_debug ;;
  281. debug-off) echo; disable_debug ;;
  282. result-proxy) set_result_proxy "$3" "$4" ;;
  283. image-proxy-on) enable_image_proxy ;;
  284. image-proxy-off) disable_image_proxy ;;
  285. *) usage "$_usage"; exit 42;;
  286. esac ;;
  287. apache)
  288. sudo_or_exit
  289. case $2 in
  290. install) install_apache_site ;;
  291. remove) remove_apache_site ;;
  292. *) usage "$_usage"; exit 42;;
  293. esac ;;
  294. doc) rst-doc;;
  295. *) usage "unknown or missing command $1"; exit 42;;
  296. esac
  297. }
  298. _service_prefix=" ${_Yellow}|$SERVICE_USER|${_creset} "
  299. install_all() {
  300. rst_title "Install SearXNG (service)"
  301. verify_continue_install
  302. pkg_install "$SEARX_PACKAGES"
  303. wait_key
  304. assert_user
  305. wait_key
  306. clone_searx
  307. wait_key
  308. install_DOT_CONFIG
  309. wait_key
  310. init_SEARX_SRC
  311. wait_key
  312. create_pyenv
  313. wait_key
  314. install_settings
  315. wait_key
  316. test_local_searx
  317. wait_key
  318. install_searx_uwsgi
  319. if ! service_is_available "http://${SEARX_INTERNAL_HTTP}"; then
  320. err_msg "URL http://${SEARX_INTERNAL_HTTP} not available, check SearXNG & uwsgi setup!"
  321. fi
  322. if ask_yn "Do you want to inspect the installation?" Ny; then
  323. inspect_service
  324. fi
  325. }
  326. install_check() {
  327. if service_account_is_available "$SERVICE_USER"; then
  328. info_msg "Service account $SERVICE_USER exists."
  329. else
  330. err_msg "Service account $SERVICE_USER does not exists!"
  331. fi
  332. if pyenv_is_available; then
  333. info_msg "~$SERVICE_USER: python environment is available."
  334. else
  335. err_msg "~$SERVICE_USER: python environment is not available!"
  336. fi
  337. if clone_is_available; then
  338. info_msg "~$SERVICE_USER: SearXNG software is installed."
  339. else
  340. err_msg "~$SERVICE_USER: Missing SearXNG software!"
  341. fi
  342. if uWSGI_app_enabled "$SEARXNG_UWSGI_APP"; then
  343. info_msg "uWSGI app $SEARXNG_UWSGI_APP is enabled."
  344. else
  345. err_msg "uWSGI app $SEARXNG_UWSGI_APP not enabled!"
  346. fi
  347. uWSGI_app_available "$SEARXNG_UWSGI_APP" \
  348. || err_msg "uWSGI app $SEARXNG_UWSGI_APP not available!"
  349. sudo -H -u "${SERVICE_USER}" "${SEARX_PYENV}/bin/python" "utils/searxng_check.py"
  350. }
  351. update_searx() {
  352. rst_title "Update SearXNG instance"
  353. echo
  354. tee_stderr 0.3 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  355. cd ${SEARX_SRC}
  356. git checkout -B "$GIT_BRANCH"
  357. git pull
  358. pip install -U pip
  359. pip install -U setuptools
  360. pip install -U wheel
  361. pip install -U pyyaml
  362. pip install -U -e .
  363. EOF
  364. install_settings
  365. uWSGI_restart "$SEARXNG_UWSGI_APP"
  366. }
  367. remove_all() {
  368. rst_title "De-Install SearXNG (service)"
  369. rst_para "\
  370. It goes without saying that this script can only be used to remove
  371. installations that were installed with this script."
  372. if ! ask_yn "Do you really want to deinstall SearXNG?"; then
  373. return
  374. fi
  375. remove_searx_uwsgi
  376. drop_service_account "${SERVICE_USER}"
  377. remove_settings
  378. wait_key
  379. if service_is_available "${PUBLIC_URL}"; then
  380. MSG="** Don't forgett to remove your public site! (${PUBLIC_URL}) **" wait_key 10
  381. fi
  382. }
  383. assert_user() {
  384. rst_title "user $SERVICE_USER" section
  385. echo
  386. if getent passwd "$SERVICE_USER" > /dev/null; then
  387. echo "user exists"
  388. return 0
  389. fi
  390. tee_stderr 1 <<EOF | bash | prefix_stdout
  391. useradd --shell /bin/bash --system \
  392. --home-dir "$SERVICE_HOME" \
  393. --comment 'Privacy-respecting metasearch engine' $SERVICE_USER
  394. mkdir "$SERVICE_HOME"
  395. chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
  396. groups $SERVICE_USER
  397. EOF
  398. #SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
  399. #export SERVICE_HOME
  400. #echo "export SERVICE_HOME=$SERVICE_HOME"
  401. }
  402. clone_is_available() {
  403. [[ -f "$SEARX_SRC/.git/config" ]]
  404. }
  405. # shellcheck disable=SC2164
  406. clone_searx() {
  407. rst_title "Clone SearXNG sources" section
  408. echo
  409. if ! sudo -i -u "$SERVICE_USER" ls -d "$REPO_ROOT" > /dev/null; then
  410. die 42 "user '$SERVICE_USER' missed read permission: $REPO_ROOT"
  411. fi
  412. SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME 2>/dev/null)"
  413. if [[ ! "${SERVICE_HOME}" ]]; then
  414. err_msg "to clone SearXNG sources, user $SERVICE_USER hast to be created first"
  415. return 42
  416. fi
  417. if [[ ! $(git show-ref "refs/heads/${GIT_BRANCH}") ]]; then
  418. warn_msg "missing local branch ${GIT_BRANCH}"
  419. info_msg "create local branch ${GIT_BRANCH} from start point: origin/${GIT_BRANCH}"
  420. git branch "${GIT_BRANCH}" "origin/${GIT_BRANCH}"
  421. fi
  422. if [[ ! $(git rev-parse --abbrev-ref HEAD) == "${GIT_BRANCH}" ]]; then
  423. warn_msg "take into account, installing branch $GIT_BRANCH while current branch is $(git rev-parse --abbrev-ref HEAD)"
  424. fi
  425. export SERVICE_HOME
  426. git_clone "$REPO_ROOT" "$SEARX_SRC" \
  427. "$GIT_BRANCH" "$SERVICE_USER"
  428. pushd "${SEARX_SRC}" > /dev/null
  429. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  430. cd "${SEARX_SRC}"
  431. git remote set-url origin ${GIT_URL}
  432. git config user.email "$ADMIN_EMAIL"
  433. git config user.name "$ADMIN_NAME"
  434. git config --list
  435. EOF
  436. popd > /dev/null
  437. }
  438. prompt_installation_status(){
  439. # shellcheck disable=SC2034
  440. local GIT_URL GIT_BRANCH VERSION_STRING VERSION_TAG
  441. local ret_val state branch remote remote_url
  442. state="$(install_searx_get_state)"
  443. case $state in
  444. missing-searx-clone|missing-searx-pyenv)
  445. info_msg "${_BBlue}(status: $(install_searx_get_state))${_creset}"
  446. return 0
  447. ;;
  448. *)
  449. info_msg "SearXNG instance already installed at: $SEARX_SRC"
  450. info_msg "status: ${_BBlue}$(install_searx_get_state)${_creset} "
  451. branch="$(git name-rev --name-only HEAD)"
  452. remote="$(git config branch."${branch}".remote)"
  453. remote_url="$(git config remote."${remote}".url)"
  454. eval "$(get_installed_version_variables)"
  455. ret_val=0
  456. if ! [ "$GIT_URL" = "$remote_url" ]; then
  457. warn_msg "instance's git URL: '${GIT_URL}'" \
  458. "differs from local clone's remote URL: ${remote_url}"
  459. ret_val=42
  460. fi
  461. if ! [ "$GIT_BRANCH" = "$branch" ]; then
  462. warn_msg "instance git branch: ${GIT_BRANCH}" \
  463. "differs from local clone's branch: ${branch}"
  464. ret_val=42
  465. fi
  466. return $ret_val
  467. ;;
  468. esac
  469. }
  470. verify_continue_install(){
  471. if ! prompt_installation_status; then
  472. MSG="[${_BCyan}KEY${_creset}] to continue installation / [${_BCyan}CTRL-C${_creset}] to exit" \
  473. wait_key
  474. fi
  475. }
  476. prompt_installation_setting(){
  477. # usage: prompt_installation_setting brand.docs_url
  478. #
  479. # Prompts the value of the (YAML) setting in the SearXNG instance.
  480. local _state
  481. _state="$(install_searx_get_state)"
  482. case $_state in
  483. python-installed|installer-modified)
  484. sudo -H -u "${SERVICE_USER}" "${SEARX_PYENV}/bin/python" <<EOF
  485. import sys
  486. from searx import get_setting
  487. name = "${1}"
  488. unset = object()
  489. value = get_setting(name, unset)
  490. if value is unset:
  491. sys.stderr.write("error: setting '%s' does not exists\n" % name)
  492. sys.exit(42)
  493. print(value)
  494. sys.exit(0)
  495. EOF
  496. ;;
  497. *)
  498. return 42
  499. ;;
  500. esac
  501. }
  502. get_installed_version_variables() {
  503. # usage: eval "$(get_installed_version_variables)"
  504. #
  505. # Set variables VERSION_STRING, VERSION_TAG, GIT_URL, GIT_BRANCH
  506. local _state
  507. _state="$(install_searx_get_state)"
  508. case $_state in
  509. python-installed|installer-modified)
  510. sudo -H -u "${SERVICE_USER}" "${SEARX_PYENV}/bin/python" -m searx.version;;
  511. *)
  512. return 42
  513. ;;
  514. esac
  515. }
  516. init_SEARX_SRC(){
  517. rst_title "Update instance: ${SEARX_SRC}/" section
  518. if ! clone_is_available; then
  519. err_msg "you have to install SearXNG first"
  520. return 1
  521. fi
  522. init_SEARX_SRC_INIT_FILES
  523. if [ ${#SEARX_SRC_INIT_FILES[*]} -eq 0 ]; then
  524. info_msg "no files registered in SEARX_SRC_INIT_FILES"
  525. return 2
  526. fi
  527. echo
  528. echo "Update instance with file(s) from: ${REPO_ROOT}"
  529. echo
  530. for i in "${SEARX_SRC_INIT_FILES[@]}"; do
  531. echo "- $i"
  532. done
  533. echo
  534. echo "Be careful when modifying an existing installation."
  535. if ! ask_yn "Do you really want to update these files in the instance?" Yn; then
  536. return 42
  537. fi
  538. for fname in "${SEARX_SRC_INIT_FILES[@]}"; do
  539. while true; do
  540. choose_one _reply "choose next step with file ${fname}" \
  541. "replace file" \
  542. "leave file unchanged" \
  543. "diff files" \
  544. "interactive shell"
  545. case $_reply in
  546. "leave file unchanged")
  547. break
  548. ;;
  549. "replace file")
  550. info_msg "copy: ${REPO_ROOT}/${fname} --> ${SEARX_SRC}/${fname}"
  551. cp "${REPO_ROOT}/${fname}" "${SEARX_SRC}/${fname}"
  552. break
  553. ;;
  554. "diff files")
  555. $DIFF_CMD "${SEARX_SRC}/${fname}" "${REPO_ROOT}/${fname}"
  556. ;;
  557. "interactive shell")
  558. backup_file "${SEARX_SRC}/${fname}"
  559. echo -e "// edit ${_Red}${dst}${_creset} to your needs"
  560. echo -e "// exit with [${_BCyan}CTRL-D${_creset}]"
  561. sudo -H -u "${SERVICE_USER}" -i
  562. $DIFF_CMD "${SEARX_SRC}/${fname}" "${REPO_ROOT}/${fname}"
  563. echo
  564. echo -e "// ${_BBlack}did you edit file ...${_creset}"
  565. echo -en "// ${_Red}${dst}${_creset}"
  566. if ask_yn "//${_BBlack}... to your needs?${_creset}"; then
  567. break
  568. fi
  569. ;;
  570. esac
  571. done
  572. done
  573. }
  574. install_DOT_CONFIG(){
  575. rst_title "Update instance: ${SEARX_SRC}/.config.sh" section
  576. if cmp --silent "${REPO_ROOT}/.config.sh" "${SEARX_SRC}/.config.sh"; then
  577. info_msg "${SEARX_SRC}/.config.sh is up to date"
  578. return 0
  579. fi
  580. diff "${REPO_ROOT}/.config.sh" "${SEARX_SRC}/.config.sh"
  581. if ! ask_yn "Do you want to copy file .config.sh into instance?" Yn; then
  582. return 42
  583. fi
  584. backup_file "${SEARX_SRC}/.config.sh"
  585. cp "${REPO_ROOT}/.config.sh" "${SEARX_SRC}/.config.sh"
  586. }
  587. install_settings() {
  588. rst_title "${SEARXNG_SETTINGS_PATH}" section
  589. if ! clone_is_available; then
  590. err_msg "you have to install SearXNG first"
  591. exit 42
  592. fi
  593. mkdir -p "$(dirname "${SEARXNG_SETTINGS_PATH}")"
  594. install_template --no-eval \
  595. "${SEARXNG_SETTINGS_PATH}" \
  596. "${SERVICE_USER}" "${SERVICE_GROUP}"
  597. configure_searx
  598. }
  599. remove_settings() {
  600. rst_title "remove SearXNG settings" section
  601. echo
  602. info_msg "delete ${SEARXNG_SETTINGS_PATH}"
  603. rm -f "${SEARXNG_SETTINGS_PATH}"
  604. }
  605. remove_searx() {
  606. rst_title "Drop searx sources" section
  607. if ask_yn "Do you really want to drop SearXNG sources ($SEARX_SRC)?"; then
  608. rm -rf "$SEARX_SRC"
  609. else
  610. rst_para "Leave SearXNG sources unchanged."
  611. fi
  612. }
  613. pyenv_is_available() {
  614. [[ -f "${SEARX_PYENV}/bin/activate" ]]
  615. }
  616. create_pyenv() {
  617. rst_title "Create virtualenv (python)" section
  618. echo
  619. if [[ ! -f "${SEARX_SRC}/manage" ]]; then
  620. err_msg "to create pyenv for SearXNG, SearXNG has to be cloned first"
  621. return 42
  622. fi
  623. info_msg "create pyenv in ${SEARX_PYENV}"
  624. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  625. rm -rf "${SEARX_PYENV}"
  626. python3 -m venv "${SEARX_PYENV}"
  627. grep -qFs -- 'source ${SEARX_PYENV}/bin/activate' ~/.profile \
  628. || echo 'source ${SEARX_PYENV}/bin/activate' >> ~/.profile
  629. EOF
  630. info_msg "inspect python's virtual environment"
  631. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  632. command -v python && python --version
  633. EOF
  634. wait_key
  635. info_msg "install needed python packages"
  636. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  637. pip install -U pip
  638. pip install -U setuptools
  639. pip install -U wheel
  640. pip install -U pyyaml
  641. cd ${SEARX_SRC}
  642. pip install -e .
  643. EOF
  644. }
  645. remove_pyenv() {
  646. rst_title "Remove virtualenv (python)" section
  647. if ! ask_yn "Do you really want to drop ${SEARX_PYENV} ?"; then
  648. return
  649. fi
  650. info_msg "remove pyenv activation from ~/.profile"
  651. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  652. grep -v 'source ${SEARX_PYENV}/bin/activate' ~/.profile > ~/.profile.##
  653. mv ~/.profile.## ~/.profile
  654. EOF
  655. rm -rf "${SEARX_PYENV}"
  656. }
  657. configure_searx() {
  658. rst_title "Configure SearXNG" section
  659. rst_para "Setup SearXNG config located at $SEARXNG_SETTINGS_PATH"
  660. echo
  661. tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
  662. cd ${SEARX_SRC}
  663. sed -i -e "s/ultrasecretkey/$(openssl rand -hex 16)/g" "$SEARXNG_SETTINGS_PATH"
  664. EOF
  665. }
  666. test_local_searx() {
  667. rst_title "Testing SearXNG instance localy" section
  668. echo
  669. if service_is_available "http://${SEARX_INTERNAL_HTTP}" &>/dev/null; then
  670. err_msg "URL/port http://${SEARX_INTERNAL_HTTP} is already in use, you"
  671. err_msg "should stop that service before starting local tests!"
  672. if ! ask_yn "Continue with local tests?"; then
  673. return
  674. fi
  675. fi
  676. sed -i -e "s/debug: false/debug: true/g" "$SEARXNG_SETTINGS_PATH"
  677. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  678. export SEARXNG_SETTINGS_PATH="${SEARXNG_SETTINGS_PATH}"
  679. cd ${SEARX_SRC}
  680. timeout 10 python searx/webapp.py &
  681. sleep 3
  682. curl --location --verbose --head --insecure $SEARX_INTERNAL_HTTP
  683. EOF
  684. sed -i -e "s/debug: true/debug: false/g" "$SEARXNG_SETTINGS_PATH"
  685. }
  686. install_searx_uwsgi() {
  687. rst_title "Install SearXNG's uWSGI app (searxng.ini)" section
  688. echo
  689. install_uwsgi
  690. uWSGI_install_app "$SEARXNG_UWSGI_APP"
  691. }
  692. remove_searx_uwsgi() {
  693. rst_title "Remove SearXNG's uWSGI app (searxng.ini)" section
  694. echo
  695. uWSGI_remove_app "$SEARXNG_UWSGI_APP"
  696. }
  697. activate_service() {
  698. rst_title "Activate SearXNG (service)" section
  699. echo
  700. uWSGI_enable_app "$SEARXNG_UWSGI_APP"
  701. uWSGI_restart "$SEARXNG_UWSGI_APP"
  702. }
  703. deactivate_service() {
  704. rst_title "De-Activate SearXNG (service)" section
  705. echo
  706. uWSGI_disable_app "$SEARXNG_UWSGI_APP"
  707. uWSGI_restart "$SEARXNG_UWSGI_APP"
  708. }
  709. enable_image_proxy() {
  710. info_msg "try to enable image_proxy ..."
  711. tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
  712. cd ${SEARX_SRC}
  713. sed -i -e "s/image_proxy: false/image_proxy: true/g" "$SEARXNG_SETTINGS_PATH"
  714. EOF
  715. uWSGI_restart "$SEARXNG_UWSGI_APP"
  716. }
  717. disable_image_proxy() {
  718. info_msg "try to enable image_proxy ..."
  719. tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
  720. cd ${SEARX_SRC}
  721. sed -i -e "s/image_proxy: true/image_proxy: false/g" "$SEARXNG_SETTINGS_PATH"
  722. EOF
  723. uWSGI_restart "$SEARXNG_UWSGI_APP"
  724. }
  725. enable_debug() {
  726. warn_msg "Do not enable debug in production environments!!"
  727. info_msg "try to enable debug mode ..."
  728. tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
  729. cd ${SEARX_SRC}
  730. sed -i -e "s/debug: false/debug: true/g" "$SEARXNG_SETTINGS_PATH"
  731. EOF
  732. uWSGI_restart "$SEARXNG_UWSGI_APP"
  733. }
  734. disable_debug() {
  735. info_msg "try to disable debug mode ..."
  736. tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
  737. cd ${SEARX_SRC}
  738. sed -i -e "s/debug: true/debug: false/g" "$SEARXNG_SETTINGS_PATH"
  739. EOF
  740. uWSGI_restart "$SEARXNG_UWSGI_APP"
  741. }
  742. set_result_proxy() {
  743. # usage: set_result_proxy <URL> [<key>]
  744. info_msg "try to set result proxy: '$1' ($2)"
  745. cp "${SEARXNG_SETTINGS_PATH}" "${SEARXNG_SETTINGS_PATH}.bak"
  746. _set_result_proxy "$1" "$2" > "${SEARXNG_SETTINGS_PATH}"
  747. }
  748. _set_result_proxy() {
  749. local line
  750. local stage=0
  751. local url=" url: $1"
  752. local key=" key: !!binary \"$2\""
  753. if [[ -z $2 ]]; then
  754. key=
  755. fi
  756. while IFS= read -r line
  757. do
  758. if [[ $stage = 0 ]] || [[ $stage = 2 ]] ; then
  759. if [[ $line =~ ^[[:space:]]*#*[[:space:]]*result_proxy[[:space:]]*:[[:space:]]*$ ]]; then
  760. if [[ $stage = 0 ]]; then
  761. stage=1
  762. echo "result_proxy:"
  763. continue
  764. elif [[ $stage = 2 ]]; then
  765. continue
  766. fi
  767. fi
  768. fi
  769. if [[ $stage = 1 ]] || [[ $stage = 2 ]] ; then
  770. if [[ $line =~ ^[[:space:]]*#*[[:space:]]*url[[:space:]]*:[[:space:]] ]]; then
  771. [[ $stage = 1 ]] && echo "$url"
  772. continue
  773. elif [[ $line =~ ^[[:space:]]*#*[[:space:]]*key[[:space:]]*:[[:space:]] ]]; then
  774. [[ $stage = 1 ]] && [[ -n $key ]] && echo "$key"
  775. continue
  776. elif [[ $line =~ ^[[:space:]]*$ ]]; then
  777. stage=2
  778. fi
  779. fi
  780. echo "$line"
  781. done < "${SEARXNG_SETTINGS_PATH}.bak"
  782. }
  783. function has_substring() {
  784. [[ "$1" != "${2/$1/}" ]]
  785. }
  786. inspect_service() {
  787. rst_title "service status & log"
  788. cat <<EOF
  789. sourced ${DOT_CONFIG} :
  790. SERVICE_USER : ${SERVICE_USER}
  791. SERVICE_HOME : ${SERVICE_HOME}
  792. EOF
  793. install_log_searx_instance
  794. install_check
  795. if in_container; then
  796. lxc_suite_info
  797. else
  798. info_msg "public URL --> ${PUBLIC_URL}"
  799. info_msg "internal URL --> http://${SEARX_INTERNAL_HTTP}"
  800. fi
  801. if ! service_is_available "http://${SEARX_INTERNAL_HTTP}"; then
  802. err_msg "uWSGI app (service) at http://${SEARX_INTERNAL_HTTP} is not available!"
  803. MSG="${_Green}[${_BCyan}CTRL-C${_Green}] to stop or [${_BCyan}KEY${_Green}] to continue"\
  804. wait_key
  805. fi
  806. if ! service_is_available "${PUBLIC_URL}"; then
  807. warn_msg "Public service at ${PUBLIC_URL} is not available!"
  808. if ! in_container; then
  809. warn_msg "Check if public name is correct and routed or use the public IP from above."
  810. fi
  811. fi
  812. local _debug_on
  813. if ask_yn "Enable SearXNG debug mode?"; then
  814. enable_debug
  815. _debug_on=1
  816. fi
  817. echo
  818. case $DIST_ID-$DIST_VERS in
  819. ubuntu-*|debian-*)
  820. systemctl --no-pager -l status "${SERVICE_NAME}"
  821. ;;
  822. arch-*)
  823. systemctl --no-pager -l status "uwsgi@${SERVICE_NAME%.*}"
  824. ;;
  825. fedora-*|centos-7)
  826. systemctl --no-pager -l status uwsgi
  827. ;;
  828. esac
  829. # shellcheck disable=SC2059
  830. printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
  831. read -r -s -n1 -t 5
  832. echo
  833. while true; do
  834. trap break 2
  835. case $DIST_ID-$DIST_VERS in
  836. ubuntu-*|debian-*) tail -f /var/log/uwsgi/app/searx.log ;;
  837. arch-*) journalctl -f -u "uwsgi@${SERVICE_NAME%.*}" ;;
  838. fedora-*|centos-7) journalctl -f -u uwsgi ;;
  839. esac
  840. done
  841. if [[ $_debug_on == 1 ]]; then
  842. disable_debug
  843. fi
  844. return 0
  845. }
  846. install_apache_site() {
  847. rst_title "Install Apache site $APACHE_SEARX_SITE"
  848. rst_para "\
  849. This installs the SearXNG uwsgi app as apache site. If your server is public to
  850. the internet, you should instead use a reverse proxy (filtron) to block
  851. excessively bot queries."
  852. ! apache_is_installed && err_msg "Apache is not installed."
  853. if ! ask_yn "Do you really want to continue?" Yn; then
  854. return
  855. else
  856. install_apache
  857. fi
  858. apache_install_site --variant=uwsgi "${APACHE_SEARX_SITE}"
  859. rst_title "Install SearXNG's uWSGI app (searxng.ini)" section
  860. echo
  861. uWSGI_install_app --variant=socket "$SEARXNG_UWSGI_APP"
  862. if ! service_is_available "${PUBLIC_URL}"; then
  863. err_msg "Public service at ${PUBLIC_URL} is not available!"
  864. fi
  865. }
  866. remove_apache_site() {
  867. rst_title "Remove Apache site ${APACHE_SEARX_SITE}"
  868. rst_para "\
  869. This removes apache site ${APACHE_SEARX_SITE}."
  870. ! apache_is_installed && err_msg "Apache is not installed."
  871. if ! ask_yn "Do you really want to continue?" Yn; then
  872. return
  873. fi
  874. apache_remove_site "${APACHE_SEARX_SITE}"
  875. rst_title "Remove SearXNG's uWSGI app (searxng.ini)" section
  876. echo
  877. uWSGI_remove_app "$SEARXNG_UWSGI_APP"
  878. }
  879. rst-doc() {
  880. local debian="${SEARX_PACKAGES_debian}"
  881. local arch="${SEARX_PACKAGES_arch}"
  882. local fedora="${SEARX_PACKAGES_fedora}"
  883. local centos="${SEARX_PACKAGES_centos}"
  884. local debian_build="${BUILD_PACKAGES_debian}"
  885. local arch_build="${BUILD_PACKAGES_arch}"
  886. local fedora_build="${BUILD_PACKAGES_fedora}"
  887. local centos_build="${SEARX_PACKAGES_centos}"
  888. debian="$(echo "${debian}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
  889. arch="$(echo "${arch}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
  890. fedora="$(echo "${fedora}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
  891. centos="$(echo "${centos}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
  892. debian_build="$(echo "${debian_build}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
  893. arch_build="$(echo "${arch_build}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
  894. fedora_build="$(echo "${fedora_build}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
  895. centos_build="$(echo "${centos_build}" | sed 's/.*/ & \\/' | sed '$ s/.$//')"
  896. eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/searx.rst")\""
  897. # I use ubuntu-20.04 here to demonstrate that versions are also suported,
  898. # normaly debian-* and ubuntu-* are most the same.
  899. for DIST_NAME in ubuntu-20.04 arch fedora; do
  900. (
  901. DIST_ID=${DIST_NAME%-*}
  902. DIST_VERS=${DIST_NAME#*-}
  903. [[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
  904. uWSGI_distro_setup
  905. echo -e "\n.. START searx uwsgi-description $DIST_NAME"
  906. case $DIST_ID-$DIST_VERS in
  907. ubuntu-*|debian-*) cat <<EOF
  908. .. code:: bash
  909. # init.d --> /usr/share/doc/uwsgi/README.Debian.gz
  910. # For uWSGI debian uses the LSB init process, this might be changed
  911. # one day, see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=833067
  912. create ${uWSGI_APPS_AVAILABLE}/${SEARXNG_UWSGI_APP}
  913. enable: sudo -H ln -s ${uWSGI_APPS_AVAILABLE}/${SEARXNG_UWSGI_APP} ${uWSGI_APPS_ENABLED}/
  914. start: sudo -H service uwsgi start ${SEARXNG_UWSGI_APP%.*}
  915. restart: sudo -H service uwsgi restart ${SEARXNG_UWSGI_APP%.*}
  916. stop: sudo -H service uwsgi stop ${SEARXNG_UWSGI_APP%.*}
  917. disable: sudo -H rm ${uWSGI_APPS_ENABLED}/${SEARXNG_UWSGI_APP}
  918. EOF
  919. ;;
  920. arch-*) cat <<EOF
  921. .. code:: bash
  922. # systemd --> /usr/lib/systemd/system/uwsgi@.service
  923. # For uWSGI archlinux uses systemd template units, see
  924. # - http://0pointer.de/blog/projects/instances.html
  925. # - https://uwsgi-docs.readthedocs.io/en/latest/Systemd.html#one-service-per-app-in-systemd
  926. create: ${uWSGI_APPS_ENABLED}/${SEARXNG_UWSGI_APP}
  927. enable: sudo -H systemctl enable uwsgi@${SEARXNG_UWSGI_APP%.*}
  928. start: sudo -H systemctl start uwsgi@${SEARXNG_UWSGI_APP%.*}
  929. restart: sudo -H systemctl restart uwsgi@${SEARXNG_UWSGI_APP%.*}
  930. stop: sudo -H systemctl stop uwsgi@${SEARXNG_UWSGI_APP%.*}
  931. disable: sudo -H systemctl disable uwsgi@${SEARXNG_UWSGI_APP%.*}
  932. EOF
  933. ;;
  934. fedora-*|centos-7) cat <<EOF
  935. .. code:: bash
  936. # systemd --> /usr/lib/systemd/system/uwsgi.service
  937. # The unit file starts uWSGI in emperor mode (/etc/uwsgi.ini), see
  938. # - https://uwsgi-docs.readthedocs.io/en/latest/Emperor.html
  939. create: ${uWSGI_APPS_ENABLED}/${SEARXNG_UWSGI_APP}
  940. restart: sudo -H touch ${uWSGI_APPS_ENABLED}/${SEARXNG_UWSGI_APP}
  941. disable: sudo -H rm ${uWSGI_APPS_ENABLED}/${SEARXNG_UWSGI_APP}
  942. EOF
  943. ;;
  944. esac
  945. echo -e ".. END searx uwsgi-description $DIST_NAME"
  946. echo -e "\n.. START searx uwsgi-appini $DIST_NAME"
  947. echo ".. code:: bash"
  948. echo
  949. eval "echo \"$(< "${TEMPLATES}/${uWSGI_APPS_AVAILABLE}/${SEARXNG_UWSGI_APP}")\"" | prefix_stdout " "
  950. echo -e "\n.. END searx uwsgi-appini $DIST_NAME"
  951. )
  952. done
  953. }
  954. # ----------------------------------------------------------------------------
  955. main "$@"
  956. # ----------------------------------------------------------------------------