searx.sh 35 KB

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