filtron.sh 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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. PUBLIC_URL="${PUBLIC_URL:-http://$(uname -n)/searx}"
  12. PUBLIC_HOST="${PUBLIC_HOST:-$(echo "$PUBLIC_URL" | sed -e 's/[^/]*\/\/\([^@]*@\)\?\([^:/]*\).*/\2/')}"
  13. FILTRON_URL_PATH="${FILTRON_URL_PATH:-$(echo "${PUBLIC_URL}" \
  14. | sed -e 's,^.*://[^/]*\(/.*\),\1,g')}"
  15. [[ "${FILTRON_URL_PATH}" == "${PUBLIC_URL}" ]] && FILTRON_URL_PATH=/
  16. FILTRON_ETC="/etc/filtron"
  17. FILTRON_RULES="$FILTRON_ETC/rules.json"
  18. FILTRON_RULES_TEMPLATE="${FILTRON_RULES_TEMPLATE:-${REPO_ROOT}/utils/templates/etc/filtron/rules.json}"
  19. FILTRON_API="${FILTRON_API:-127.0.0.1:4005}"
  20. FILTRON_LISTEN="${FILTRON_LISTEN:-127.0.0.1:4004}"
  21. FILTRON_TARGET="${FILTRON_TARGET:-127.0.0.1:8888}"
  22. SERVICE_NAME="filtron"
  23. SERVICE_USER="${SERVICE_USER:-${SERVICE_NAME}}"
  24. SERVICE_HOME_BASE="${SERVICE_HOME_BASE:-/usr/local}"
  25. SERVICE_HOME="${SERVICE_HOME_BASE}/${SERVICE_USER}"
  26. SERVICE_SYSTEMD_UNIT="${SYSTEMD_UNITS}/${SERVICE_NAME}.service"
  27. # shellcheck disable=SC2034
  28. SERVICE_GROUP="${SERVICE_USER}"
  29. # shellcheck disable=SC2034
  30. SERVICE_GROUP="${SERVICE_USER}"
  31. GO_ENV="${SERVICE_HOME}/.go_env"
  32. GO_PKG_URL="https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz"
  33. GO_TAR=$(basename "$GO_PKG_URL")
  34. APACHE_FILTRON_SITE="searx.conf"
  35. NGINX_FILTRON_SITE="searx.conf"
  36. # shellcheck disable=SC2034
  37. CONFIG_FILES=(
  38. "${FILTRON_RULES}"
  39. "${SERVICE_SYSTEMD_UNIT}"
  40. )
  41. # ----------------------------------------------------------------------------
  42. usage() {
  43. # ----------------------------------------------------------------------------
  44. # shellcheck disable=SC1117
  45. cat <<EOF
  46. usage::
  47. $(basename "$0") shell
  48. $(basename "$0") install [all|user|rules]
  49. $(basename "$0") update [filtron]
  50. $(basename "$0") remove [all]
  51. $(basename "$0") activate [service]
  52. $(basename "$0") deactivate [service]
  53. $(basename "$0") inspect [service]
  54. $(basename "$0") option [debug-on|debug-off]
  55. $(basename "$0") apache [install|remove]
  56. $(basename "$0") nginx [install|remove]
  57. shell
  58. start interactive shell from user ${SERVICE_USER}
  59. install / remove
  60. :all: complete setup of filtron service
  61. :user: add/remove service user '$SERVICE_USER' ($SERVICE_HOME)
  62. :rules: reinstall filtron rules $FILTRON_RULES
  63. update filtron
  64. Update filtron installation ($SERVICE_HOME)
  65. activate service
  66. activate and start service daemon (systemd unit)
  67. deactivate service
  68. stop and deactivate service daemon (systemd unit)
  69. inspect service
  70. show service status and log
  71. option
  72. set one of the available options
  73. apache (${PUBLIC_URL})
  74. :install: apache site with a reverse proxy (ProxyPass)
  75. :remove: apache site ${APACHE_FILTRON_SITE}
  76. nginx (${PUBLIC_URL})
  77. :install: nginx site with a reverse proxy (ProxyPass)
  78. :remove: nginx site ${NGINX_FILTRON_SITE}
  79. filtron rules: ${FILTRON_RULES_TEMPLATE}
  80. ---- sourced ${DOT_CONFIG} :
  81. SERVICE_USER : ${SERVICE_USER}
  82. SERVICE_HOME : ${SERVICE_HOME}
  83. FILTRON_TARGET : ${FILTRON_TARGET}
  84. FILTRON_API : ${FILTRON_API}
  85. FILTRON_LISTEN : ${FILTRON_LISTEN}
  86. FILTRON_URL_PATH : ${FILTRON_URL_PATH}
  87. EOF
  88. install_log_searx_instance
  89. [[ -n ${1} ]] && err_msg "$1"
  90. }
  91. main() {
  92. required_commands \
  93. sudo install git wget curl \
  94. || exit
  95. local _usage="unknown or missing $1 command $2"
  96. case $1 in
  97. --getenv) var="$2"; echo "${!var}"; exit 0;;
  98. -h|--help) usage; exit 0;;
  99. shell)
  100. sudo_or_exit
  101. interactive_shell "${SERVICE_USER}"
  102. ;;
  103. inspect)
  104. case $2 in
  105. service)
  106. sudo_or_exit
  107. inspect_service
  108. ;;
  109. *) usage "$_usage"; exit 42;;
  110. esac ;;
  111. install)
  112. rst_title "$SERVICE_NAME" part
  113. sudo_or_exit
  114. case $2 in
  115. all) install_all ;;
  116. user) assert_user ;;
  117. rules)
  118. install_rules
  119. systemd_restart_service "${SERVICE_NAME}"
  120. ;;
  121. *) usage "$_usage"; exit 42;;
  122. esac ;;
  123. update)
  124. sudo_or_exit
  125. case $2 in
  126. filtron) update_filtron ;;
  127. *) usage "$_usage"; exit 42;;
  128. esac ;;
  129. remove)
  130. sudo_or_exit
  131. case $2 in
  132. all) remove_all;;
  133. user) drop_service_account "${SERVICE_USER}" ;;
  134. *) usage "$_usage"; exit 42;;
  135. esac ;;
  136. activate)
  137. sudo_or_exit
  138. case $2 in
  139. service) systemd_activate_service "${SERVICE_NAME}" ;;
  140. *) usage "$_usage"; exit 42;;
  141. esac ;;
  142. deactivate)
  143. sudo_or_exit
  144. case $2 in
  145. service) systemd_deactivate_service "${SERVICE_NAME}" ;;
  146. *) usage "$_usage"; exit 42;;
  147. esac ;;
  148. apache)
  149. sudo_or_exit
  150. case $2 in
  151. install) install_apache_site ;;
  152. remove) remove_apache_site ;;
  153. *) usage "$_usage"; exit 42;;
  154. esac ;;
  155. nginx)
  156. sudo_or_exit
  157. case $2 in
  158. install) install_nginx_site ;;
  159. remove) remove_nginx_site ;;
  160. *) usage "$_usage"; exit 42;;
  161. esac ;;
  162. option)
  163. sudo_or_exit
  164. case $2 in
  165. debug-on) echo; enable_debug ;;
  166. debug-off) echo; disable_debug ;;
  167. *) usage "$_usage"; exit 42;;
  168. esac ;;
  169. doc) rst-doc ;;
  170. *) usage "unknown or missing command $1"; exit 42;;
  171. esac
  172. }
  173. install_all() {
  174. rst_title "Install $SERVICE_NAME (service)"
  175. assert_user
  176. wait_key
  177. install_go "${GO_PKG_URL}" "${GO_TAR}" "${SERVICE_USER}"
  178. wait_key
  179. install_filtron
  180. install_rules
  181. wait_key
  182. systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  183. wait_key
  184. echo
  185. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  186. err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
  187. fi
  188. if apache_is_installed; then
  189. info_msg "Apache is installed on this host."
  190. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  191. install_apache_site
  192. fi
  193. elif nginx_is_installed; then
  194. info_msg "nginx is installed on this host."
  195. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  196. install_nginx_site
  197. fi
  198. fi
  199. if ask_yn "Do you want to inspect the installation?" Ny; then
  200. inspect_service
  201. fi
  202. }
  203. remove_all() {
  204. rst_title "De-Install $SERVICE_NAME (service)"
  205. rst_para "\
  206. It goes without saying that this script can only be used to remove
  207. installations that were installed with this script."
  208. if ! systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
  209. return 42
  210. fi
  211. drop_service_account "${SERVICE_USER}"
  212. rm -r "$FILTRON_ETC" 2>&1 | prefix_stdout
  213. if service_is_available "${PUBLIC_URL}"; then
  214. MSG="** Don't forget to remove your public site! (${PUBLIC_URL}) **" wait_key 10
  215. fi
  216. }
  217. assert_user() {
  218. rst_title "user $SERVICE_USER" section
  219. echo
  220. tee_stderr 1 <<EOF | bash | prefix_stdout
  221. useradd --shell /bin/bash --system \
  222. --home-dir "$SERVICE_HOME" \
  223. --comment 'Reverse HTTP proxy to filter requests' $SERVICE_USER
  224. mkdir "$SERVICE_HOME"
  225. chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
  226. groups $SERVICE_USER
  227. EOF
  228. SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
  229. export SERVICE_HOME
  230. echo "export SERVICE_HOME=$SERVICE_HOME"
  231. cat > "$GO_ENV" <<EOF
  232. export GOPATH=\$HOME/go-apps
  233. export PATH=\$PATH:\$HOME/local/go/bin:\$GOPATH/bin
  234. EOF
  235. echo "Environment $GO_ENV has been setup."
  236. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER"
  237. grep -qFs -- 'source $GO_ENV' ~/.profile || echo 'source $GO_ENV' >> ~/.profile
  238. EOF
  239. }
  240. filtron_is_installed() {
  241. [[ -f $SERVICE_HOME/go-apps/bin/filtron ]]
  242. }
  243. _svcpr=" ${_Yellow}|${SERVICE_USER}|${_creset} "
  244. install_filtron() {
  245. rst_title "Install filtron in user's ~/go-apps" section
  246. echo
  247. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  248. go get -v -u github.com/asciimoo/filtron
  249. EOF
  250. }
  251. update_filtron() {
  252. rst_title "Update filtron" section
  253. echo
  254. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  255. go get -v -u github.com/asciimoo/filtron
  256. EOF
  257. }
  258. install_rules() {
  259. rst_title "Install filtron rules"
  260. echo
  261. if [[ ! -f "${FILTRON_RULES}" ]]; then
  262. info_msg "install rules ${FILTRON_RULES_TEMPLATE}"
  263. info_msg " --> ${FILTRON_RULES}"
  264. mkdir -p "$(dirname "${FILTRON_RULES}")"
  265. cp "${FILTRON_RULES_TEMPLATE}" "${FILTRON_RULES}"
  266. return
  267. fi
  268. rst_para "Diff between origin's rules file (+) and current (-):"
  269. echo "${FILTRON_RULES}" "${FILTRON_RULES_TEMPLATE}"
  270. $DIFF_CMD "${FILTRON_RULES}" "${FILTRON_RULES_TEMPLATE}"
  271. local action
  272. choose_one action "What should happen to the rules file? " \
  273. "keep configuration unchanged" \
  274. "use origin rules" \
  275. "start interactive shell"
  276. case $action in
  277. "keep configuration unchanged")
  278. info_msg "leave rules file unchanged"
  279. ;;
  280. "use origin rules")
  281. backup_file "${FILTRON_RULES}"
  282. info_msg "install origin rules"
  283. cp "${FILTRON_RULES_TEMPLATE}" "${FILTRON_RULES}"
  284. ;;
  285. "start interactive shell")
  286. backup_file "${FILTRON_RULES}"
  287. echo -e "// exit with [${_BCyan}CTRL-D${_creset}]"
  288. sudo -H -i
  289. rst_para 'Diff between new rules file (-) and current (+):'
  290. echo
  291. $DIFF_CMD "${FILTRON_RULES_TEMPLATE}" "${FILTRON_RULES}"
  292. wait_key
  293. ;;
  294. esac
  295. }
  296. inspect_service() {
  297. rst_title "service status & log"
  298. cat <<EOF
  299. sourced ${DOT_CONFIG} :
  300. SERVICE_USER : ${SERVICE_USER}
  301. SERVICE_HOME : ${SERVICE_HOME}
  302. FILTRON_TARGET : ${FILTRON_TARGET}
  303. FILTRON_API : ${FILTRON_API}
  304. FILTRON_LISTEN : ${FILTRON_LISTEN}
  305. FILTRON_URL_PATH : ${FILTRON_URL_PATH}
  306. EOF
  307. install_log_searx_instance
  308. if service_account_is_available "$SERVICE_USER"; then
  309. info_msg "service account $SERVICE_USER available."
  310. else
  311. err_msg "service account $SERVICE_USER not available!"
  312. fi
  313. if go_is_available "$SERVICE_USER"; then
  314. info_msg "~$SERVICE_USER: go is installed"
  315. else
  316. err_msg "~$SERVICE_USER: go is not installed"
  317. fi
  318. if filtron_is_installed; then
  319. info_msg "~$SERVICE_USER: filtron app is installed"
  320. else
  321. err_msg "~$SERVICE_USER: filtron app is not installed!"
  322. fi
  323. if ! service_is_available "http://${FILTRON_API}"; then
  324. err_msg "API not available at: http://${FILTRON_API}"
  325. fi
  326. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  327. err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
  328. fi
  329. if service_is_available "http://${FILTRON_TARGET}" ; then
  330. info_msg "Filtron's target is available at: http://${FILTRON_TARGET}"
  331. fi
  332. if ! service_is_available "${PUBLIC_URL}"; then
  333. warn_msg "Public service at ${PUBLIC_URL} is not available!"
  334. if ! in_container; then
  335. warn_msg "Check if public name is correct and routed or use the public IP from above."
  336. fi
  337. fi
  338. if in_container; then
  339. lxc_suite_info
  340. else
  341. info_msg "public URL --> ${PUBLIC_URL}"
  342. info_msg "internal URL --> http://${FILTRON_LISTEN}"
  343. fi
  344. local _debug_on
  345. if ask_yn "Enable filtron debug mode?"; then
  346. enable_debug
  347. _debug_on=1
  348. fi
  349. echo
  350. systemctl --no-pager -l status "${SERVICE_NAME}"
  351. echo
  352. info_msg "public URL --> ${PUBLIC_URL}"
  353. # shellcheck disable=SC2059
  354. printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
  355. read -r -s -n1 -t 5
  356. echo
  357. while true; do
  358. trap break 2
  359. journalctl -f -u "${SERVICE_NAME}"
  360. done
  361. if [[ $_debug_on == 1 ]]; then
  362. disable_debug
  363. fi
  364. return 0
  365. }
  366. enable_debug() {
  367. info_msg "try to enable debug mode ..."
  368. python <<EOF
  369. import sys, json
  370. debug = {
  371. u'name': u'debug request'
  372. , u'filters': []
  373. , u'interval': 0
  374. , u'limit': 0
  375. , u'actions': [{u'name': u'log'}]
  376. }
  377. with open('$FILTRON_RULES') as rules:
  378. j = json.load(rules)
  379. pos = None
  380. for i in range(len(j)):
  381. if j[i].get('name') == 'debug request':
  382. pos = i
  383. break
  384. if pos is not None:
  385. j[pos] = debug
  386. else:
  387. j.append(debug)
  388. with open('$FILTRON_RULES', 'w') as rules:
  389. json.dump(j, rules, indent=2, sort_keys=True)
  390. EOF
  391. systemctl restart "${SERVICE_NAME}.service"
  392. }
  393. disable_debug() {
  394. info_msg "try to disable debug mode ..."
  395. python <<EOF
  396. import sys, json
  397. with open('$FILTRON_RULES') as rules:
  398. j = json.load(rules)
  399. pos = None
  400. for i in range(len(j)):
  401. if j[i].get('name') == 'debug request':
  402. pos = i
  403. break
  404. if pos is not None:
  405. del j[pos]
  406. with open('$FILTRON_RULES', 'w') as rules:
  407. json.dump(j, rules, indent=2, sort_keys=True)
  408. EOF
  409. systemctl restart "${SERVICE_NAME}.service"
  410. }
  411. install_apache_site() {
  412. rst_title "Install Apache site $APACHE_FILTRON_SITE"
  413. rst_para "\
  414. This installs a reverse proxy (ProxyPass) into apache site (${APACHE_FILTRON_SITE})"
  415. ! apache_is_installed && info_msg "Apache is not installed."
  416. if ! ask_yn "Do you really want to continue?" Yn; then
  417. return
  418. else
  419. install_apache
  420. fi
  421. "${REPO_ROOT}/utils/searx.sh" install uwsgi
  422. apache_install_site --variant=filtron "${APACHE_FILTRON_SITE}"
  423. info_msg "testing public url .."
  424. if ! service_is_available "${PUBLIC_URL}"; then
  425. err_msg "Public service at ${PUBLIC_URL} is not available!"
  426. fi
  427. }
  428. remove_apache_site() {
  429. rst_title "Remove Apache site $APACHE_FILTRON_SITE"
  430. rst_para "\
  431. This removes apache site ${APACHE_FILTRON_SITE}."
  432. ! apache_is_installed && err_msg "Apache is not installed."
  433. if ! ask_yn "Do you really want to continue?" Yn; then
  434. return
  435. fi
  436. apache_remove_site "$APACHE_FILTRON_SITE"
  437. }
  438. install_nginx_site() {
  439. rst_title "Install nginx site $NGINX_FILTRON_SITE"
  440. rst_para "\
  441. This installs a reverse proxy (ProxyPass) into nginx site (${NGINX_FILTRON_SITE})"
  442. ! nginx_is_installed && info_msg "nginx is not installed."
  443. if ! ask_yn "Do you really want to continue?" Yn; then
  444. return
  445. else
  446. install_nginx
  447. fi
  448. "${REPO_ROOT}/utils/searx.sh" install uwsgi
  449. # shellcheck disable=SC2034
  450. SEARX_SRC=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_SRC)
  451. # shellcheck disable=SC2034
  452. SEARX_URL_PATH=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_URL_PATH)
  453. nginx_install_app --variant=filtron "${NGINX_FILTRON_SITE}"
  454. info_msg "testing public url .."
  455. if ! service_is_available "${PUBLIC_URL}"; then
  456. err_msg "Public service at ${PUBLIC_URL} is not available!"
  457. fi
  458. }
  459. remove_nginx_site() {
  460. rst_title "Remove nginx site $NGINX_FILTRON_SITE"
  461. rst_para "\
  462. This removes nginx site ${NGINX_FILTRON_SITE}."
  463. ! nginx_is_installed && err_msg "nginx is not installed."
  464. if ! ask_yn "Do you really want to continue?" Yn; then
  465. return
  466. fi
  467. nginx_remove_site "$FILTRON_FILTRON_SITE"
  468. }
  469. rst-doc() {
  470. eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/filtron.rst")\""
  471. echo -e "\n.. START install systemd unit"
  472. cat <<EOF
  473. .. tabs::
  474. .. group-tab:: systemd
  475. .. code:: bash
  476. EOF
  477. eval "echo \"$(< "${TEMPLATES}/${SERVICE_SYSTEMD_UNIT}")\"" | prefix_stdout " "
  478. echo -e "\n.. END install systemd unit"
  479. # for DIST_NAME in ubuntu-20.04 arch fedora centos; do
  480. # (
  481. # DIST_ID=${DIST_NAME%-*}
  482. # DIST_VERS=${DIST_NAME#*-}
  483. # [[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
  484. # # ...
  485. # )
  486. # done
  487. }
  488. # ----------------------------------------------------------------------------
  489. main "$@"
  490. # ----------------------------------------------------------------------------