morty.sh 16 KB

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