searx.sh 32 KB

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