morty.sh 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. #!/usr/bin/env bash
  2. # -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
  3. # SPDX-License-Identifier: AGPL-3.0-or-later
  4. # shellcheck source=utils/lib.sh
  5. source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
  6. # shellcheck source=utils/brand.env
  7. source "${REPO_ROOT}/utils/brand.env"
  8. source_dot_config
  9. SEARX_URL="${PUBLIC_URL:-http://$(uname -n)/searx}"
  10. source "${REPO_ROOT}/utils/lxc-searx.env"
  11. in_container && lxc_set_suite_env
  12. # ----------------------------------------------------------------------------
  13. # config
  14. # ----------------------------------------------------------------------------
  15. MORTY_LISTEN="${MORTY_LISTEN:-127.0.0.1:3000}"
  16. PUBLIC_URL_PATH_MORTY="${PUBLIC_URL_PATH_MORTY:-/morty/}"
  17. PUBLIC_URL_MORTY="${PUBLIC_URL_MORTY:-$(echo "$SEARX_URL" | sed -e's,^\(.*://[^/]*\).*,\1,g')${PUBLIC_URL_PATH_MORTY}}"
  18. # shellcheck disable=SC2034
  19. MORTY_TIMEOUT=5
  20. SERVICE_NAME="morty"
  21. SERVICE_USER="${SERVICE_USER:-${SERVICE_NAME}}"
  22. SERVICE_HOME_BASE="${SERVICE_HOME_BASE:-/usr/local}"
  23. SERVICE_HOME="${SERVICE_HOME_BASE}/${SERVICE_USER}"
  24. SERVICE_SYSTEMD_UNIT="${SYSTEMD_UNITS}/${SERVICE_NAME}.service"
  25. # shellcheck disable=SC2034
  26. SERVICE_GROUP="${SERVICE_USER}"
  27. # shellcheck disable=SC2034
  28. SERVICE_ENV_DEBUG=false
  29. GO_ENV="${SERVICE_HOME}/.go_env"
  30. GO_PKG_URL="https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz"
  31. GO_TAR=$(basename "$GO_PKG_URL")
  32. # shellcheck disable=SC2034
  33. CONFIG_FILES=()
  34. # Apache Settings
  35. APACHE_MORTY_SITE="morty.conf"
  36. NGINX_MORTY_SITE="morty.conf"
  37. # ----------------------------------------------------------------------------
  38. usage() {
  39. # ----------------------------------------------------------------------------
  40. # shellcheck disable=SC1117
  41. cat <<EOF
  42. usage::
  43. $(basename "$0") shell
  44. $(basename "$0") install [all|user]
  45. $(basename "$0") update [morty]
  46. $(basename "$0") remove [all]
  47. $(basename "$0") activate [service]
  48. $(basename "$0") deactivate [service]
  49. $(basename "$0") inspect [service]
  50. $(basename "$0") option [debug-on|debug-off]
  51. $(basename "$0") apache [install|remove]
  52. $(basename "$0") nginx [install|remove]
  53. $(basename "$0") info [searx]
  54. shell
  55. start interactive shell from user ${SERVICE_USER}
  56. install / remove
  57. all: complete setup of morty service
  58. user: add/remove service user '$SERVICE_USER' ($SERVICE_HOME)
  59. update morty
  60. Update morty installation ($SERVICE_HOME)
  61. activate service
  62. activate and start service daemon (systemd unit)
  63. deactivate service
  64. stop and deactivate service daemon (systemd unit)
  65. inspect service
  66. show service status and log
  67. option
  68. set one of the available options
  69. apache : ${PUBLIC_URL_MORTY}
  70. :install: apache site with a reverse proxy (ProxyPass)
  71. :remove: apache site ${APACHE_MORTY_SITE}
  72. nginx (${PUBLIC_URL_MORTY})
  73. :install: nginx site with a reverse proxy (ProxyPass)
  74. :remove: nginx site ${NGINX_MORTY_SITE}
  75. If needed, set the environment variables in the '${DOT_CONFIG#"$REPO_ROOT/"}' file::
  76. PUBLIC_URL_MORTY: ${PUBLIC_URL_MORTY}
  77. MORTY_LISTEN: ${MORTY_LISTEN}
  78. SERVICE_USER: ${SERVICE_USER}
  79. EOF
  80. if in_container; then
  81. # in containers the service is listening on 0.0.0.0 (see lxc-searx.env)
  82. for ip in $(global_IPs) ; do
  83. if [[ $ip =~ .*:.* ]]; then
  84. echo " container URL (IPv6): http://[${ip#*|}]:3000/"
  85. else
  86. # IPv4:
  87. echo " container URL (IPv4): http://${ip#*|}:3000/"
  88. fi
  89. done
  90. fi
  91. echo
  92. info_searx
  93. [[ -n ${1} ]] && err_msg "$1"
  94. }
  95. info_searx() {
  96. # shellcheck disable=SC1117
  97. cat <<EOF
  98. To activate result and image proxy in searx, edit settings.yml (read:
  99. ${DOCS_URL}/admin/morty.html)::
  100. result_proxy:
  101. url : ${PUBLIC_URL_MORTY}
  102. server:
  103. image_proxy : True
  104. EOF
  105. }
  106. main() {
  107. required_commands \
  108. sudo install git wget curl \
  109. || exit
  110. local _usage="ERROR: unknown or missing $1 command $2"
  111. case $1 in
  112. --getenv) var="$2"; echo "${!var}"; exit 0;;
  113. -h|--help) usage; exit 0;;
  114. shell)
  115. sudo_or_exit
  116. interactive_shell "${SERVICE_USER}"
  117. ;;
  118. inspect)
  119. case $2 in
  120. service)
  121. sudo_or_exit
  122. inspect_service
  123. ;;
  124. *) usage "$_usage"; exit 42;;
  125. esac ;;
  126. install)
  127. rst_title "$SERVICE_NAME" part
  128. sudo_or_exit
  129. case $2 in
  130. all) install_all ;;
  131. user) assert_user ;;
  132. *) usage "$_usage"; exit 42;;
  133. esac ;;
  134. update)
  135. sudo_or_exit
  136. case $2 in
  137. morty) update_morty ;;
  138. *) usage "$_usage"; exit 42;;
  139. esac ;;
  140. remove)
  141. sudo_or_exit
  142. case $2 in
  143. all) remove_all;;
  144. user) drop_service_account "${SERVICE_USER}" ;;
  145. *) usage "$_usage"; exit 42;;
  146. esac ;;
  147. activate)
  148. sudo_or_exit
  149. case $2 in
  150. service) systemd_activate_service "${SERVICE_NAME}" ;;
  151. *) usage "$_usage"; exit 42;;
  152. esac ;;
  153. deactivate)
  154. sudo_or_exit
  155. case $2 in
  156. service) systemd_deactivate_service "${SERVICE_NAME}" ;;
  157. *) usage "$_usage"; exit 42;;
  158. esac ;;
  159. apache)
  160. sudo_or_exit
  161. case $2 in
  162. install) install_apache_site ;;
  163. remove) remove_apache_site ;;
  164. *) usage "$_usage"; exit 42;;
  165. esac ;;
  166. nginx)
  167. sudo_or_exit
  168. case $2 in
  169. install) install_nginx_site ;;
  170. remove) remove_nginx_site ;;
  171. *) usage "$_usage"; exit 42;;
  172. esac ;;
  173. info)
  174. case $2 in
  175. searx) info_searx ;;
  176. *) usage "$_usage"; exit 42;;
  177. esac ;;
  178. option)
  179. sudo_or_exit
  180. case $2 in
  181. debug-on) enable_debug ;;
  182. debug-off) disable_debug ;;
  183. *) usage "$_usage"; exit 42;;
  184. esac ;;
  185. doc) rst-doc ;;
  186. *) usage "ERROR: unknown or missing command $1"; exit 42;;
  187. esac
  188. }
  189. install_all() {
  190. MORTY_KEY="$(head -c 32 /dev/urandom | base64)"
  191. rst_title "Install $SERVICE_NAME (service)"
  192. assert_user
  193. wait_key
  194. install_go "${GO_PKG_URL}" "${GO_TAR}" "${SERVICE_USER}"
  195. wait_key
  196. install_morty
  197. wait_key
  198. systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  199. wait_key
  200. if ! service_is_available "http://${MORTY_LISTEN}" ; then
  201. err_msg "Morty does not listening on: http://${MORTY_LISTEN}"
  202. fi
  203. if apache_is_installed; then
  204. info_msg "Apache is installed on this host."
  205. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  206. install_apache_site
  207. fi
  208. elif nginx_is_installed; then
  209. info_msg "nginx is installed on this host."
  210. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  211. install_nginx_site
  212. fi
  213. fi
  214. info_searx
  215. if ask_yn "Add image and result proxy to searx settings.yml?" Yn; then
  216. "${REPO_ROOT}/utils/searx.sh" option result-proxy "${PUBLIC_URL_MORTY}" "${MORTY_KEY}"
  217. "${REPO_ROOT}/utils/searx.sh" option image-proxy-on
  218. fi
  219. if ask_yn "Do you want to inspect the installation?" Ny; then
  220. inspect_service
  221. fi
  222. }
  223. remove_all() {
  224. rst_title "De-Install $SERVICE_NAME (service)"
  225. rst_para "\
  226. It goes without saying that this script can only be used to remove
  227. installations that were installed with this script."
  228. if systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
  229. drop_service_account "${SERVICE_USER}"
  230. fi
  231. }
  232. assert_user() {
  233. rst_title "user $SERVICE_USER" section
  234. echo
  235. tee_stderr 1 <<EOF | bash | prefix_stdout
  236. useradd --shell /bin/bash --system \
  237. --home-dir "$SERVICE_HOME" \
  238. --comment 'Web content sanitizer proxy' $SERVICE_USER
  239. mkdir "$SERVICE_HOME"
  240. chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
  241. groups $SERVICE_USER
  242. EOF
  243. SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
  244. export SERVICE_HOME
  245. echo "export SERVICE_HOME=$SERVICE_HOME"
  246. cat > "$GO_ENV" <<EOF
  247. export GOPATH=\$HOME/go-apps
  248. export PATH=\$PATH:\$HOME/local/go/bin:\$GOPATH/bin
  249. EOF
  250. echo "Environment $GO_ENV has been setup."
  251. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER"
  252. grep -qFs -- 'source $GO_ENV' ~/.profile || echo 'source $GO_ENV' >> ~/.profile
  253. EOF
  254. }
  255. morty_is_installed() {
  256. [[ -f $SERVICE_HOME/go-apps/bin/morty ]]
  257. }
  258. _svcpr=" ${_Yellow}|${SERVICE_USER}|${_creset} "
  259. install_morty() {
  260. rst_title "Install morty in user's ~/go-apps" section
  261. echo
  262. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  263. go get -v -u github.com/asciimoo/morty
  264. EOF
  265. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  266. cd \$GOPATH/src/github.com/asciimoo/morty
  267. go test
  268. go test -benchmem -bench .
  269. EOF
  270. }
  271. update_morty() {
  272. rst_title "Update morty" section
  273. echo
  274. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  275. go get -v -u github.com/asciimoo/morty
  276. EOF
  277. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  278. cd \$GOPATH/src/github.com/asciimoo/morty
  279. go test
  280. go test -benchmem -bench .
  281. EOF
  282. }
  283. set_service_env_debug() {
  284. # usage: set_service_env_debug [false|true]
  285. # shellcheck disable=SC2034
  286. local SERVICE_ENV_DEBUG="${1:-false}"
  287. if systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
  288. systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  289. fi
  290. }
  291. inspect_service() {
  292. rst_title "service status & log"
  293. cat <<EOF
  294. sourced ${DOT_CONFIG#"$REPO_ROOT/"} :
  295. MORTY_LISTEN : ${MORTY_LISTEN}
  296. EOF
  297. if service_account_is_available "$SERVICE_USER"; then
  298. info_msg "service account $SERVICE_USER available."
  299. else
  300. err_msg "service account $SERVICE_USER not available!"
  301. fi
  302. if go_is_available "$SERVICE_USER"; then
  303. info_msg "~$SERVICE_USER: go is installed"
  304. else
  305. err_msg "~$SERVICE_USER: go is not installed"
  306. fi
  307. if morty_is_installed; then
  308. info_msg "~$SERVICE_USER: morty app is installed"
  309. else
  310. err_msg "~$SERVICE_USER: morty app is not installed!"
  311. fi
  312. if ! service_is_available "http://${MORTY_LISTEN}" ; then
  313. err_msg "Morty does not listening on: http://${MORTY_LISTEN}"
  314. echo -e "${_Green}stop with [${_BCyan}CTRL-C${_Green}] or .."
  315. wait_key
  316. fi
  317. if ! service_is_available "${PUBLIC_URL_MORTY}"; then
  318. warn_msg "Public service at ${PUBLIC_URL_MORTY} is not available!"
  319. if ! in_container; then
  320. warn_msg "Check if public name is correct and routed or use the public IP from above."
  321. fi
  322. fi
  323. if in_container; then
  324. lxc_suite_info
  325. else
  326. info_msg "public URL --> ${PUBLIC_URL_MORTY}"
  327. info_msg "morty URL --> http://${MORTY_LISTEN}"
  328. fi
  329. local _debug_on
  330. if ask_yn "Enable morty debug mode (needs reinstall of systemd service)?"; then
  331. enable_debug
  332. _debug_on=1
  333. else
  334. systemctl --no-pager -l status "${SERVICE_NAME}"
  335. fi
  336. echo
  337. # shellcheck disable=SC2059
  338. printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
  339. read -r -s -n1 -t 5
  340. echo
  341. while true; do
  342. trap break 2
  343. journalctl -f -u "${SERVICE_NAME}"
  344. done
  345. if [[ $_debug_on == 1 ]]; then
  346. FORCE_SELECTION=Y disable_debug
  347. fi
  348. return 0
  349. }
  350. enable_debug() {
  351. warn_msg "Do not enable debug in production enviroments!!"
  352. info_msg "Enabling debug option needs to reinstall systemd service!"
  353. set_service_env_debug true
  354. }
  355. disable_debug() {
  356. info_msg "Disabling debug option needs to reinstall systemd service!"
  357. set_service_env_debug false
  358. }
  359. install_apache_site() {
  360. rst_title "Install Apache site $APACHE_MORTY_SITE"
  361. rst_para "\
  362. This installs a reverse proxy (ProxyPass) into apache site (${APACHE_MORTY_SITE})"
  363. ! apache_is_installed && err_msg "Apache is not installed."
  364. if ! ask_yn "Do you really want to continue?" Yn; then
  365. return
  366. else
  367. install_apache
  368. fi
  369. apache_install_site "${APACHE_MORTY_SITE}"
  370. info_msg "testing public url .."
  371. if ! service_is_available "${PUBLIC_URL_MORTY}"; then
  372. err_msg "Public service at ${PUBLIC_URL_MORTY} is not available!"
  373. fi
  374. }
  375. remove_apache_site() {
  376. rst_title "Remove Apache site $APACHE_MORTY_SITE"
  377. rst_para "\
  378. This removes apache site ${APACHE_MORTY_SITE}."
  379. ! apache_is_installed && err_msg "Apache is not installed."
  380. if ! ask_yn "Do you really want to continue?" Yn; then
  381. return
  382. fi
  383. apache_remove_site "$APACHE_MORTY_SITE"
  384. }
  385. install_nginx_site() {
  386. rst_title "Install nginx site $NGINX_MORTY_SITE"
  387. rst_para "\
  388. This installs a reverse proxy (ProxyPass) into nginx site (${NGINX_MORTY_SITE})"
  389. ! nginx_is_installed && err_msg "nginx is not installed."
  390. if ! ask_yn "Do you really want to continue?" Yn; then
  391. return
  392. else
  393. install_nginx
  394. fi
  395. "${REPO_ROOT}/utils/searx.sh" install uwsgi
  396. # shellcheck disable=SC2034
  397. SEARX_SRC=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_SRC)
  398. # shellcheck disable=SC2034
  399. SEARX_URL_PATH=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_URL_PATH)
  400. nginx_install_app "${NGINX_MORTY_SITE}"
  401. info_msg "testing public url .."
  402. if ! service_is_available "${PUBLIC_URL_MORTY}"; then
  403. err_msg "Public service at ${PUBLIC_URL_MORTY} is not available!"
  404. fi
  405. }
  406. remove_nginx_site() {
  407. rst_title "Remove nginx site $NGINX_MORTY_SITE"
  408. rst_para "\
  409. This removes nginx site ${NGINX_MORTY_SITE}."
  410. ! nginx_is_installed && err_msg "nginx is not installed."
  411. if ! ask_yn "Do you really want to continue?" Yn; then
  412. return
  413. fi
  414. nginx_remove_site "$NGINX_MORTY_SITE"
  415. }
  416. rst-doc() {
  417. eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/morty.rst")\""
  418. echo -e "\n.. START install systemd unit"
  419. cat <<EOF
  420. .. tabs::
  421. .. group-tab:: systemd
  422. .. code:: bash
  423. EOF
  424. eval "echo \"$(< "${TEMPLATES}/${SERVICE_SYSTEMD_UNIT}")\"" | prefix_stdout " "
  425. echo -e "\n.. END install systemd unit"
  426. # for DIST_NAME in ubuntu-20.04 arch fedora; do
  427. # (
  428. # DIST_ID=${DIST_NAME%-*}
  429. # DIST_VERS=${DIST_NAME#*-}
  430. # [[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
  431. # # ...
  432. # )
  433. # done
  434. }
  435. # ----------------------------------------------------------------------------
  436. main "$@"
  437. # ----------------------------------------------------------------------------