morty.sh 15 KB

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