searx.sh 34 KB

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