searx.sh 34 KB

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