searx.sh 34 KB

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