searx.sh 33 KB

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