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 searx, edit settings.yml (read:
  98. ${DOCS_URL}/admin/morty.html)::
  99. result_proxy:
  100. url : ${PUBLIC_URL_MORTY}
  101. server:
  102. image_proxy : True
  103. EOF
  104. }
  105. main() {
  106. required_commands \
  107. sudo install git wget curl \
  108. || exit
  109. local _usage="ERROR: unknown or missing $1 command $2"
  110. case $1 in
  111. --getenv) var="$2"; echo "${!var}"; exit 0;;
  112. -h|--help) usage; exit 0;;
  113. shell)
  114. sudo_or_exit
  115. interactive_shell "${SERVICE_USER}"
  116. ;;
  117. inspect)
  118. case $2 in
  119. service)
  120. sudo_or_exit
  121. inspect_service
  122. ;;
  123. *) usage "$_usage"; exit 42;;
  124. esac ;;
  125. install)
  126. rst_title "$SERVICE_NAME" part
  127. sudo_or_exit
  128. case $2 in
  129. all) install_all ;;
  130. user) assert_user ;;
  131. *) usage "$_usage"; exit 42;;
  132. esac ;;
  133. update)
  134. sudo_or_exit
  135. case $2 in
  136. morty) update_morty ;;
  137. *) usage "$_usage"; exit 42;;
  138. esac ;;
  139. remove)
  140. sudo_or_exit
  141. case $2 in
  142. all) remove_all;;
  143. user) drop_service_account "${SERVICE_USER}" ;;
  144. *) usage "$_usage"; exit 42;;
  145. esac ;;
  146. activate)
  147. sudo_or_exit
  148. case $2 in
  149. service) systemd_activate_service "${SERVICE_NAME}" ;;
  150. *) usage "$_usage"; exit 42;;
  151. esac ;;
  152. deactivate)
  153. sudo_or_exit
  154. case $2 in
  155. service) systemd_deactivate_service "${SERVICE_NAME}" ;;
  156. *) usage "$_usage"; exit 42;;
  157. esac ;;
  158. apache)
  159. sudo_or_exit
  160. case $2 in
  161. install) install_apache_site ;;
  162. remove) remove_apache_site ;;
  163. *) usage "$_usage"; exit 42;;
  164. esac ;;
  165. nginx)
  166. sudo_or_exit
  167. case $2 in
  168. install) install_nginx_site ;;
  169. remove) remove_nginx_site ;;
  170. *) usage "$_usage"; exit 42;;
  171. esac ;;
  172. info)
  173. case $2 in
  174. searx) info_searx ;;
  175. *) usage "$_usage"; exit 42;;
  176. esac ;;
  177. option)
  178. sudo_or_exit
  179. case $2 in
  180. new-key) set_new_key ;;
  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} :
  295. SERVICE_USER : ${SERVICE_USER}
  296. SERVICE_HOME : ${SERVICE_HOME}
  297. PUBLIC_URL_MORTY: : ${PUBLIC_URL_MORTY}
  298. MORTY_LISTEN: : ${MORTY_LISTEN}
  299. EOF
  300. install_log_searx_instance
  301. if service_account_is_available "$SERVICE_USER"; then
  302. info_msg "service account $SERVICE_USER available."
  303. else
  304. err_msg "service account $SERVICE_USER not available!"
  305. fi
  306. if go_is_available "$SERVICE_USER"; then
  307. info_msg "~$SERVICE_USER: go is installed"
  308. else
  309. err_msg "~$SERVICE_USER: go is not installed"
  310. fi
  311. if morty_is_installed; then
  312. info_msg "~$SERVICE_USER: morty app is installed"
  313. else
  314. err_msg "~$SERVICE_USER: morty app is not installed!"
  315. fi
  316. if ! service_is_available "http://${MORTY_LISTEN}" ; then
  317. err_msg "Morty does not listening on: http://${MORTY_LISTEN}"
  318. echo -e "${_Green}stop with [${_BCyan}CTRL-C${_Green}] or .."
  319. wait_key
  320. fi
  321. if ! service_is_available "${PUBLIC_URL_MORTY}"; then
  322. warn_msg "Public service at ${PUBLIC_URL_MORTY} is not available!"
  323. if ! in_container; then
  324. warn_msg "Check if public name is correct and routed or use the public IP from above."
  325. fi
  326. fi
  327. if in_container; then
  328. lxc_suite_info
  329. else
  330. info_msg "public URL --> ${PUBLIC_URL_MORTY}"
  331. info_msg "morty URL --> http://${MORTY_LISTEN}"
  332. fi
  333. local _debug_on
  334. if ask_yn "Enable morty debug mode (needs reinstall of systemd service)?"; then
  335. enable_debug
  336. _debug_on=1
  337. else
  338. systemctl --no-pager -l status "${SERVICE_NAME}"
  339. fi
  340. echo
  341. # shellcheck disable=SC2059
  342. printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
  343. read -r -s -n1 -t 5
  344. echo
  345. while true; do
  346. trap break 2
  347. journalctl -f -u "${SERVICE_NAME}"
  348. done
  349. if [[ $_debug_on == 1 ]]; then
  350. FORCE_SELECTION=Y disable_debug
  351. fi
  352. return 0
  353. }
  354. enable_debug() {
  355. warn_msg "Do not enable debug in production environments!!"
  356. info_msg "Enabling debug option needs to reinstall systemd service!"
  357. set_service_env_debug true
  358. }
  359. disable_debug() {
  360. info_msg "Disabling debug option needs to reinstall systemd service!"
  361. set_service_env_debug false
  362. }
  363. set_new_key() {
  364. rst_title "Set morty key"
  365. echo
  366. MORTY_KEY="$(head -c 32 /dev/urandom | base64)"
  367. info_msg "morty key: '${MORTY_KEY}'"
  368. warn_msg "this will need to reinstall services .."
  369. MSG="${_Green}press any [${_BCyan}KEY${_Green}] to continue // stop with [${_BCyan}CTRL-C${_creset}]" wait_key
  370. systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  371. "${REPO_ROOT}/utils/searx.sh" option result-proxy "${PUBLIC_URL_MORTY}" "${MORTY_KEY}"
  372. "${REPO_ROOT}/utils/searx.sh" option image-proxy-on
  373. }
  374. install_apache_site() {
  375. rst_title "Install Apache site $APACHE_MORTY_SITE"
  376. rst_para "\
  377. This installs a reverse proxy (ProxyPass) into apache site (${APACHE_MORTY_SITE})"
  378. ! apache_is_installed && err_msg "Apache is not installed."
  379. if ! ask_yn "Do you really want to continue?" Yn; then
  380. return
  381. else
  382. install_apache
  383. fi
  384. apache_install_site "${APACHE_MORTY_SITE}"
  385. info_msg "testing public url .."
  386. if ! service_is_available "${PUBLIC_URL_MORTY}"; then
  387. err_msg "Public service at ${PUBLIC_URL_MORTY} is not available!"
  388. fi
  389. }
  390. remove_apache_site() {
  391. rst_title "Remove Apache site $APACHE_MORTY_SITE"
  392. rst_para "\
  393. This removes apache site ${APACHE_MORTY_SITE}."
  394. ! apache_is_installed && err_msg "Apache is not installed."
  395. if ! ask_yn "Do you really want to continue?" Yn; then
  396. return
  397. fi
  398. apache_remove_site "$APACHE_MORTY_SITE"
  399. }
  400. install_nginx_site() {
  401. rst_title "Install nginx site $NGINX_MORTY_SITE"
  402. rst_para "\
  403. This installs a reverse proxy (ProxyPass) into nginx site (${NGINX_MORTY_SITE})"
  404. ! nginx_is_installed && err_msg "nginx is not installed."
  405. if ! ask_yn "Do you really want to continue?" Yn; then
  406. return
  407. else
  408. install_nginx
  409. fi
  410. "${REPO_ROOT}/utils/searx.sh" install uwsgi
  411. # shellcheck disable=SC2034
  412. SEARX_SRC=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_SRC)
  413. # shellcheck disable=SC2034
  414. SEARX_URL_PATH=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_URL_PATH)
  415. nginx_install_app "${NGINX_MORTY_SITE}"
  416. info_msg "testing public url .."
  417. if ! service_is_available "${PUBLIC_URL_MORTY}"; then
  418. err_msg "Public service at ${PUBLIC_URL_MORTY} is not available!"
  419. fi
  420. }
  421. remove_nginx_site() {
  422. rst_title "Remove nginx site $NGINX_MORTY_SITE"
  423. rst_para "\
  424. This removes nginx site ${NGINX_MORTY_SITE}."
  425. ! nginx_is_installed && err_msg "nginx is not installed."
  426. if ! ask_yn "Do you really want to continue?" Yn; then
  427. return
  428. fi
  429. nginx_remove_site "$NGINX_MORTY_SITE"
  430. }
  431. rst-doc() {
  432. eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/morty.rst")\""
  433. echo -e "\n.. START install systemd unit"
  434. cat <<EOF
  435. .. tabs::
  436. .. group-tab:: systemd
  437. .. code:: bash
  438. EOF
  439. eval "echo \"$(< "${TEMPLATES}/${SERVICE_SYSTEMD_UNIT}")\"" | prefix_stdout " "
  440. echo -e "\n.. END install systemd unit"
  441. # for DIST_NAME in ubuntu-20.04 arch fedora centos; do
  442. # (
  443. # DIST_ID=${DIST_NAME%-*}
  444. # DIST_VERS=${DIST_NAME#*-}
  445. # [[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
  446. # # ...
  447. # )
  448. # done
  449. }
  450. # ----------------------------------------------------------------------------
  451. main "$@"
  452. # ----------------------------------------------------------------------------