searx.sh 33 KB

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