install-prod.sh 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #!/usr/bin/env sh
  2. set -eu
  3. # Listmonk production setup using `docker-compose`.
  4. # See https://listmonk.app/docs/installation/ for detailed installation steps.
  5. printf '\n'
  6. RED="$(tput setaf 1 2>/dev/null || printf '')"
  7. BLUE="$(tput setaf 4 2>/dev/null || printf '')"
  8. GREEN="$(tput setaf 2 2>/dev/null || printf '')"
  9. NO_COLOR="$(tput sgr0 2>/dev/null || printf '')"
  10. info() {
  11. printf '%s\n' "${BLUE}> ${NO_COLOR} $*"
  12. }
  13. error() {
  14. printf '%s\n' "${RED}x $*${NO_COLOR}" >&2
  15. }
  16. completed() {
  17. printf '%s\n' "${GREEN}✓ ${NO_COLOR} $*"
  18. }
  19. exists() {
  20. command -v "$1" 1>/dev/null 2>&1
  21. }
  22. check_dependencies() {
  23. if ! exists curl; then
  24. error "curl is not installed."
  25. exit 1
  26. fi
  27. if ! exists docker; then
  28. error "docker is not installed."
  29. exit 1
  30. fi
  31. if ! exists docker-compose; then
  32. error "docker-compose is not installed."
  33. exit 1
  34. fi
  35. }
  36. download() {
  37. curl --fail --silent --location --output "$2" "$1"
  38. }
  39. is_healthy() {
  40. info "waiting for db container to be up. retrying in 3s"
  41. health_status="$(docker inspect -f "{{.State.Health.Status}}" "$1")"
  42. if [ "$health_status" = "healthy" ]; then
  43. return 0
  44. else
  45. return 1
  46. fi
  47. }
  48. is_running() {
  49. info "checking if "$1" is running"
  50. status="$(docker inspect -f "{{.State.Status}}" "$1")"
  51. if [ "$status" = "running" ]; then
  52. return 0
  53. else
  54. return 1
  55. fi
  56. }
  57. generate_password(){
  58. echo $(tr -dc A-Za-z0-9 </dev/urandom | head -c 13 ; echo '')
  59. }
  60. get_config() {
  61. info "fetching config.toml from listmonk repo"
  62. download https://raw.githubusercontent.com/knadh/listmonk/master/config.toml.sample config.toml
  63. }
  64. get_containers() {
  65. info "fetching docker-compose.yml from listmonk repo"
  66. download https://raw.githubusercontent.com/knadh/listmonk/master/docker-compose.yml docker-compose.yml
  67. }
  68. modify_config(){
  69. info "generating a random password"
  70. db_password=$(generate_password)
  71. info "modifying config.toml"
  72. # Replace `db.host=localhost` with `db.host=db` in config file.
  73. sed -i "s/host = \"localhost\"/host = \"listmonk_db\"/g" config.toml
  74. # Replace `db.password=listmonk` with `db.password={{db_password}}` in config file.
  75. # Note that `password` is wrapped with `\b`. This ensures that `admin_password` doesn't match this pattern instead.
  76. sed -i "s/\bpassword\b = \"listmonk\"/password = \"$db_password\"/g" config.toml
  77. # Replace `app.address=localhost:9000` with `app.address=0.0.0.0:9000` in config file.
  78. sed -i "s/address = \"localhost:9000\"/address = \"0.0.0.0:9000\"/g" config.toml
  79. info "modifying docker-compose.yml"
  80. sed -i "s/POSTGRES_PASSWORD=listmonk/POSTGRES_PASSWORD=$db_password/g" docker-compose.yml
  81. }
  82. run_migrations(){
  83. info "running migrations"
  84. docker-compose up -d db
  85. while ! is_healthy listmonk_db; do sleep 3; done
  86. docker-compose run --rm app ./listmonk --install
  87. }
  88. start_services(){
  89. info "starting app"
  90. docker-compose up -d app db
  91. }
  92. show_output(){
  93. info "finishing setup"
  94. sleep 3
  95. if is_running listmonk_db && is_running listmonk_app
  96. then completed "Listmonk is now up and running. Visit http://localhost:9000 in your browser."
  97. else
  98. error "error running containers. something went wrong."
  99. fi
  100. }
  101. check_dependencies
  102. get_config
  103. get_containers
  104. modify_config
  105. run_migrations
  106. start_services
  107. show_output