First pass in moving to debian
[discourse_docker.git] / discourse-setup
old mode 100644 (file)
new mode 100755 (executable)
index 797f5a8..c4f263b
-#!/bin/bash
+#!/usr/bin/env bash
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+cd $DIR
+
+##
+## Make sure only root can run our script
+##
+check_root() {
+  if [[ $EUID -ne 0 ]]; then
+    echo "This script must be run as root. Please sudo or log in as root first." 1>&2
+    exit 1
+  fi
+}
+
+##
+## Check whether a connection to HOSTNAME ($1) on PORT ($2) is possible
+##
+connect_to_port () {
+  HOST="$1"
+  PORT="$2"
+  VERIFY=`date +%s | sha256sum | base64 | head -c 20`
+  echo -e "HTTP/1.1 200 OK\n\n $VERIFY" | nc -w 4 -l -p $PORT >/dev/null 2>&1 &
+  if curl --proto =http -s $HOST:$PORT --connect-timeout 3 | grep $VERIFY >/dev/null 2>&1
+  then
+      return 0
+  else
+    curl --proto =http -s localhost:$PORT >/dev/null 2>&1
+    return 1
+  fi
+}
+
+check_IP_match () {
+  HOST="$1"
+  echo
+  echo Checking your domain name . . .
+  if connect_to_port $HOST 443
+  then
+      echo
+      echo "Connection to $HOST succeeded."
+  else
+    echo WARNING:: This server does not appear to be accessible at $HOST:443.
+    echo
+    if connect_to_port $HOST 80
+    then
+       echo A connection to port 80 succeeds, however.
+       echo This suggests that your DNS settings are correct,
+       echo but something is keeping traffic to port 443 from getting to your server.
+       echo Check your networking configuration to see that connections to port 443 are allowed.
+    else
+      echo "A connection to http://$HOST (port 80) also fails."
+      echo
+      echo This suggests that $HOST resolves to the wrong IP address
+      echo or that traffic is not being routed to your server.
+    fi
+    echo
+    echo Google: \"open ports YOUR CLOUD SERVICE\" for information for resolving this problem.
+    echo
+    echo You should probably answer \"n\" at the next prompt and disable Let\'s Encrypt.
+    echo
+    echo This test might not work for all situations,
+    echo so if you can access Discourse at http://$HOST, you might try anyway.
+    sleep 3
+  fi
+}
+
+##
+## Do we have docker?
+##
+check_and_install_docker () {
+  docker_path=`which docker.io || which docker`
+  if [ -z $docker_path ]; then
+    read  -p "Docker not installed. Enter to install from https://get.docker.com/ or Ctrl+C to exit"
+    curl https://get.docker.com/ | sh
+  fi
+  docker_path=`which docker.io || which docker`
+  if [ -z $docker_path ]; then
+    echo Docker install failed. Quitting.
+    exit
+  fi
+}
+
+##
+## What are we running on
+##
+check_OS() {
+  echo `uname -s`
+}
+
+##
+## OS X available memory
+##
+check_osx_memory() {
+  echo `free -m | awk '/Mem:/ {print $2}'`
+}
+
+##
+## Linux available memory
+##
+check_linux_memory() {
+  echo `free -g --si | awk ' /Mem:/  {print $2} '`
+}
 
 ##
 ## Do we have enough memory and disk space for Discourse?
 ##
 check_disk_and_memory() {
-  
-  resources="ok"
-  avail_mem="$(LANG=C free -m | grep '^Mem:' | awk '{print $2}')"
-  if [ "$avail_mem" -lt 900 ]; then
-    resources="insufficient"
-    echo "WARNING: You do not appear to have sufficient memory to run Discourse."
-    echo
-    echo "Your system may not work properly, or future upgrades of Discourse may"
-    echo "not complete successfully."
+
+  os_type=$(check_OS)
+  avail_mem=0
+  if [ "$os_type" == "Darwin" ]; then
+    avail_mem=$(check_osx_memory)
+  else
+    avail_mem=$(check_linux_memory)
+  fi
+
+  if [ "$avail_mem" -lt 1 ]; then
+    echo "WARNING: Discourse requires 1GB RAM to run. This system does not appear"
+    echo "to have sufficient memory."
     echo
-    echo "See https://github.com/discourse/discourse/blob/master/docs/INSTALL-cloud.md#create-new-cloud-server"
-  elif [ "$avail_mem" -lt 1800 ]; then
-    total_swap="$(LANG=C free -m | grep ^Swap: | awk '{print $2}')"
-    if [ "$total_swap" -lt 1000 ]; then
-      resources="insufficient"
-      echo "WARNING: You must have at least 1GB of swap when running with less"
-      echo "than 2GB of RAM."
+    echo "Your site may not work properly, or future upgrades of Discourse may not"
+    echo "complete successfully."
+    exit 1
+  fi
+
+  if [ "$avail_mem" -le 2 ]; then
+    total_swap=`free -g --si | awk ' /Swap:/  {print $2} '`
+
+    if [ "$total_swap" -lt 2 ]; then
+      echo "WARNING: Discourse requires at least 2GB of swap when running with 2GB of RAM"
+      echo "or less. This system does not appear to have sufficient swap space."
       echo
-      echo "Your system may not work properly, or future upgrades of Discourse may"
-      echo "not complete successfully."
+      echo "Without sufficient swap space, your site may not work properly, and future"
+      echo "upgrades of Discourse may not complete successfully."
       echo
-      echo "See https://github.com/discourse/discourse/blob/master/docs/INSTALL-cloud.md#set-up-swap-if-needed"
+      echo "Ctrl+C to exit or wait 5 seconds to have a 2GB swapfile created."
+      sleep 5
+
+      ##
+      ## derived from https://meta.discourse.org/t/13880
+      ##
+      install -o root -g root -m 0600 /dev/null /swapfile
+      dd if=/dev/zero of=/swapfile bs=1k count=2048k
+      mkswap /swapfile
+      swapon /swapfile
+      echo "/swapfile       swap    swap    auto      0       0" | tee -a /etc/fstab
+      sysctl -w vm.swappiness=10
+      echo 'vm.swappiness = 10' > /etc/sysctl.d/30-discourse-swap.conf
+
+      total_swap=`free -g --si | awk ' /Swap:/ {print $2} '`
+      if [ "$total_swap" -lt 2 ]; then
+        echo "Failed to create swap: are you root? Are you running on real hardware, or a fully virtualized server?"
+        exit 1
+      fi
+
     fi
   fi
 
+
   free_disk="$(df /var | tail -n 1 | awk '{print $4}')"
   if [ "$free_disk" -lt 5000 ]; then
-    resources="insufficient"
-    echo "WARNING: You must have at least 5GB of *free* disk space to run Discourse."
+    echo "WARNING: Discourse requires at least 5GB free disk space. This system"
+    echo "does not appear to have sufficient disk space."
     echo
-    echo "Insufficient disk space may result in problems running your site, and may"
-    echo "not even allow Discourse installation to complete successfully."
+    echo "Insufficient disk space may result in problems running your site, and"
+    echo "may not even allow Discourse installation to complete successfully."
     echo
     echo "Please free up some space, or expand your disk, before continuing."
     echo
-    echo "Run \`apt-get autoremove && apt-get autoclean\` to clean up unused packages and \`./launcher cleanup\` to remove stale Docker containers."
+    echo "Run \`apt-get autoremove && apt-get autoclean\` to clean up unused"
+    echo "packages and \`./launcher cleanup\` to remove stale Docker containers."
     exit 1
   fi
 
-  if [ -t 0 ] && [ "$resources" != "ok" ]; then
-    echo
-    read -p "Press ENTER to continue, or Ctrl-C to exit and give your system more resources"
-  fi
 }
 
 
@@ -55,10 +179,18 @@ check_disk_and_memory() {
 ##
 scale_ram_and_cpu() {
 
+  local changelog=/tmp/changelog.$PPID
   # grab info about total system ram and physical (NOT LOGICAL!) CPU cores
-  avail_mem="$(LANG=C free -m | grep '^Mem:' | awk '{print $2}')"
-  avail_gb=$(( $avail_mem / 950 ))
-  avail_cores=`cat /proc/cpuinfo | grep "cpu cores" | uniq | awk '{print $4}'`
+  avail_gb=0
+  avail_cores=0
+  os_type=$(check_OS)
+  if [ "$os_type" == "Darwin" ]; then
+    avail_gb=$(check_osx_memory)
+    avail_cores=`sysctl hw.ncpu | awk '/hw.ncpu:/ {print $2}'`
+  else
+    avail_gb=$(check_linux_memory)
+    avail_cores=$((`awk '/cpu cores/ {print $4;exit}' /proc/cpuinfo`*`sort /proc/cpuinfo | uniq | grep -c "physical id"`))
+  fi
   echo "Found ${avail_gb}GB of memory and $avail_cores physical CPU cores"
 
   # db_shared_buffers: 128MB for 1GB, 256MB for 2GB, or 256MB * GB, max 4096MB
@@ -75,14 +207,13 @@ scale_ram_and_cpu() {
   fi
   db_shared_buffers=$(( db_shared_buffers < 4096 ? db_shared_buffers : 4096 ))
 
-  sed -i -e "s/^  #db_shared_buffers:.*/  db_shared_buffers: \"${db_shared_buffers}MB\"/w $changelog" $config_file
+  sed -i -e "s/^  #\?db_shared_buffers:.*/  db_shared_buffers: \"${db_shared_buffers}MB\"/w $changelog" $data_file
   if [ -s $changelog ]
   then
     echo "setting db_shared_buffers = ${db_shared_buffers}MB"
     rm $changelog
   fi
 
-
   # UNICORN_WORKERS: 2 * GB for 2GB or less, or 2 * CPU, max 8
   if [ "$avail_gb" -le "2" ]
   then
@@ -92,17 +223,18 @@ scale_ram_and_cpu() {
   fi
   unicorn_workers=$(( unicorn_workers < 8 ? unicorn_workers : 8 ))
 
-  sed -i -e "s/^  #UNICORN_WORKERS:.*/  UNICORN_WORKERS: ${unicorn_workers}/w $changelog" $config_file
+  sed -i -e "s/^  #\?UNICORN_WORKERS:.*/  UNICORN_WORKERS: ${unicorn_workers}/w $changelog" $web_file
   if [ -s $changelog ]
   then
       echo "setting UNICORN_WORKERS = ${unicorn_workers}"
       rm $changelog
   fi
 
+  echo $data_file memory parameters updated.
 }
 
 
-## 
+##
 ## standard http / https ports must not be occupied
 ##
 check_ports() {
@@ -116,97 +248,175 @@ check_ports() {
 ## check a port to see if it is already in use
 ##
 check_port() {
-  
+
   local valid=$(netstat -tln | awk '{print $4}' | grep ":${1}\$")
 
   if [ -n "$valid" ]; then
     echo "Port ${1} appears to already be in use."
     echo
-    echo "If you are trying to run Discourse simultaneously with another web server like Apache or nginx, you will need to bind to a different port -- see https://meta.discourse.org/t/17247 for help."
+    echo "This will show you what command is using port ${1}"
+    lsof -i tcp:${1} -s tcp:listen
+    echo
+    echo "If you are trying to run Discourse simultaneously with another web"
+    echo "server like Apache or nginx, you will need to bind to a different port"
+    echo
+    echo "See https://meta.discourse.org/t/17247"
+    echo
+    echo "If you are reconfiguring an already-configured Discourse, use "
+    echo
+    echo "./launcher stop app"
+    echo
+    echo "to stop Discourse before you reconfigure it and try again."
     exit 1
   fi
 }
 
+##
+## read a variable from the config file
+##
+read_config() {
+  config_line=`egrep "^  #?$1:" $web_file`
+  read_config_result=`echo $config_line | awk  -F":" '{print $2}'`
+  read_config_result=`echo $read_config_result | sed "s/^\([\"']\)\(.*\)\1\$/\2/g"`
+}
+
+read_default() {
+  config_line=`egrep "^  #?$1:" samples/standalone.yml`
+  read_default_result=`echo $config_line | awk  -F":" '{print $2}'`
+  read_default_result=`echo $read_config_result | sed "s/^\([\"']\)\(.*\)\1\$/\2/g"`
+}
+
 ##
 ## prompt user for typical Discourse config file values
 ##
-set_config() {
-  
-  local hostname="discourse.example.com"
-  local developer_emails="me@example.com"
-  local smtp_address="smtp.example.com"
-  local smtp_user_name="postmaster@discourse.example.com"
-  local smtp_password=""
-  local letsencrypt_account_email="me@example.com"
-  local letsencrypt_status="ENTER to skip"
+ask_user_for_config() {
+
+  # NOTE: Defaults now come from standalone.yml
+
+  local changelog=/tmp/changelog.$PPID
+  read_config "DISCOURSE_SMTP_ADDRESS"
+  local smtp_address=$read_config_result
+  # NOTE: if there are spaces between emails, this breaks, but a human should be paying attention
+  read_config "DISCOURSE_DEVELOPER_EMAILS"
+  local developer_emails=$read_config_result
+  read_config "DISCOURSE_SMTP_PASSWORD"
+  local smtp_password=$read_config_result
+  read_config "DISCOURSE_SMTP_PORT"
+  local smtp_port=$read_config_result
+  read_config "DISCOURSE_SMTP_USER_NAME"
+  local smtp_user_name=$read_config_result
+  if [ "$smtp_password" = "pa$$word" ]
+  then
+      smtp_password = ""
+  fi
+  read_config "LETSENCRYPT_ACCOUNT_EMAIL"
+  local letsencrypt_account_email=$read_config_result
+  if [ -z $letsencrypt_account_email ]
+  then
+      letsencrypt_account_email="me@example.com"
+  fi
+  if [ "$letsencrypt_account_email" = "me@example.com" ]
+  then
+      local letsencrypt_status="ENTER to skip"
+  else
+    local letsencrypt_status="Enter 'OFF' to disable."
+  fi
+
+  read_config "DISCOURSE_HOSTNAME"
+  hostname=$read_config_result
 
   local new_value=""
   local config_ok="n"
   local update_ok="y"
-  
+
   echo ""
 
   while [[ "$config_ok" == "n" ]]
   do
-    if [ ! -z $hostname ]
+    if [ ! -z "$hostname" ]
     then
       read -p "Hostname for your Discourse? [$hostname]: " new_value
-      if [ ! -z $new_value ]
+      if [ ! -z "$new_value" ]
+      then
+          hostname="$new_value"
+      fi
+      if [[ $hostname =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
       then
-          hostname=$new_value
+        echo
+        echo "Discourse requires a DNS hostname. IP addresses are unsupported and will not work."
+        echo
+        hostname="discourse.example.com"
       fi
     fi
-    
-    if [ ! -z $developer_emails ]
+
+    if [ ! -z "$developer_emails" ]
     then
-      read -p "Email address for admin account? [$developer_emails]: " new_value
-      if [ ! -z $new_value ]
+      read -p "Email address for admin account(s)? [$developer_emails]: " new_value
+      if [ ! -z "$new_value" ]
       then
-          developer_emails=$new_value
+          developer_emails="$new_value"
       fi
     fi
-    
-    if [ ! -z $smtp_address ]
+
+    if [ ! -z "$smtp_address" ]
     then
       read -p "SMTP server address? [$smtp_address]: " new_value
-      if [ ! -z $new_value ]
+      if [ ! -z "$new_value" ]
       then
-        smtp_address=$new_value
+        smtp_address="$new_value"
       fi
     fi
-    
-    if [ "$smtp_address" == "smtp.sparkpostmail.com" ]
+
+    if [ ! -z "$smtp_port" ]
     then
-       smtp_user_name="SMTP_Injection"
+      read -p "SMTP port? [$smtp_port]: " new_value
+      if [ ! -z "$new_value" ]
+      then
+        smtp_port="$new_value"
+      fi
     fi
-    
-    if [ "$smtp_address" == "smtp.sendgrid.net" ]
+
+    ##
+    ## automatically set correct user name based on common mail providers unless it's been set
+    ##
+    if [ "$smtp_user_name" == "user@example.com" ]
     then
-           smtp_user_name="apikey"
+      if [ "$smtp_address" == "smtp.sparkpostmail.com" ]
+      then
+       smtp_user_name="SMTP_Injection"
+      fi
+      if [ "$smtp_address" == "smtp.sendgrid.net" ]
+      then
+           smtp_user_name="apikey"
+      fi
+      if [ "$smtp_address" == "smtp.mailgun.org" ]
+      then
+           smtp_user_name="postmaster@$hostname"
+      fi
     fi
-    
-    if [ ! -z $smtp_user_name ]
+
+    if [ ! -z "$smtp_user_name" ]
     then
       read -p "SMTP user name? [$smtp_user_name]: " new_value
-      if [ ! -z $new_value ]
+      if [ ! -z "$new_value" ]
       then
-          smtp_user_name=$new_value
+          smtp_user_name="$new_value"
       fi
     fi
-    
+
     read -p "SMTP password? [$smtp_password]: " new_value
-    if [ ! -z $new_value ]
+    if [ ! -z "$new_value" ]
     then
-        smtp_password=$new_value
+        smtp_password="$new_value"
     fi
-    
+
     if [ ! -z $letsencrypt_account_email ]
     then
-      read -p "Let's Encrypt account email? ($letsencrypt_status) [$letsencrypt_account_email]: " new_value
-      if [ ! -z $new_value ]
+      read -p "Optional email address for setting up Let's Encrypt? ($letsencrypt_status) [$letsencrypt_account_email]: " new_value
+      if [ ! -z "$new_value" ]
       then
-          letsencrypt_account_email=$new_value
-          if [ "$new_value" == "off" ]
+          letsencrypt_account_email="$new_value"
+          if [ "${new_value,,}" = "off" ]
           then
             letsencrypt_status="ENTER to skip"
           else
@@ -215,23 +425,30 @@ set_config() {
       fi
     fi
 
-    echo -e "\nThat's it! Everything is set. Does this look right?\n"
+    if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
+    then
+       check_IP_match $hostname
+    fi
+
+    echo -e "\nDoes this look right?\n"
     echo "Hostname      : $hostname"
     echo "Email         : $developer_emails"
     echo "SMTP address  : $smtp_address"
+    echo "SMTP port     : $smtp_port"
     echo "SMTP username : $smtp_user_name"
     echo "SMTP password : $smtp_password"
-    
+
     if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
     then
       echo "Let's Encrypt : $letsencrypt_account_email"
     fi
-    
+
+
     echo ""
-    read -p "Press ENTER to continue, 'n' to try again, or ^C to exit: " config_ok
+    read -p "ENTER to continue, 'n' to try again, Ctrl+C to exit: " config_ok
   done
 
-  sed -i -e "s/^  DISCOURSE_HOSTNAME: 'discourse.example.com'/  DISCOURSE_HOSTNAME: $hostname/w $changelog" $config_file
+  sed -i -e "s/^  DISCOURSE_HOSTNAME:.*/  DISCOURSE_HOSTNAME: $hostname/w $changelog" $web_file
   if [ -s $changelog ]
   then
     rm $changelog
@@ -240,7 +457,7 @@ set_config() {
     update_ok="n"
   fi
 
-  sed -i -e "s/^  DISCOURSE_DEVELOPER_EMAILS:.*/  DISCOURSE_DEVELOPER_EMAILS: \'$developer_emails\'/w $changelog" $config_file
+  sed -i -e "s/^  DISCOURSE_DEVELOPER_EMAILS:.*/  DISCOURSE_DEVELOPER_EMAILS: \'$developer_emails\'/w $changelog" $web_file
   if [ -s $changelog ]
   then
     rm $changelog
@@ -249,7 +466,7 @@ set_config() {
     update_ok="n"
   fi
 
-  sed -i -e "s/^  DISCOURSE_SMTP_ADDRESS: smtp.example.com.*/  DISCOURSE_SMTP_ADDRESS: $smtp_address/w $changelog" $config_file
+  sed -i -e "s/^  DISCOURSE_SMTP_ADDRESS:.*/  DISCOURSE_SMTP_ADDRESS: $smtp_address/w $changelog" $web_file
   if [ -s $changelog ]
   then
     rm $changelog
@@ -258,27 +475,87 @@ set_config() {
     update_ok="n"
   fi
 
-  sed -i -e "s/^  #DISCOURSE_SMTP_USER_NAME: user@example.com.*/  DISCOURSE_SMTP_USER_NAME: $smtp_user_name/w $changelog" $config_file
+  sed -i -e "s/^  #\?DISCOURSE_SMTP_PORT:.*/  DISCOURSE_SMTP_PORT: $smtp_port/w $changelog" $web_file
   if [ -s $changelog ]
   then
     rm $changelog
   else
-    echo "DISCOURSE_SMTP_USER_NAME change failed."
+    echo "DISCOURSE_SMTP_PORT change failed."
     update_ok="n"
   fi
 
-  sed -i -e "s/^  #DISCOURSE_SMTP_PASSWORD: pa\$\$word.*/  DISCOURSE_SMTP_PASSWORD: $smtp_password/w $changelog" $config_file
+  sed -i -e "s/^  #\?DISCOURSE_SMTP_USER_NAME:.*/  DISCOURSE_SMTP_USER_NAME: $smtp_user_name/w $changelog" $web_file
   if [ -s $changelog ]
   then
-      rm $changelog
+    rm $changelog
   else
-    echo "DISCOURSE_SMTP_PASSWORD change failed."
+    echo "DISCOURSE_SMTP_USER_NAME change failed."
     update_ok="n"
   fi
 
-  if [ "$letsencrypt_status" != "ENTER to skip" ]
+  if [[ "$smtp_password" == *"\""* ]]
   then
-      sed -i -e "s/^  #LETSENCRYPT_ACCOUNT_EMAIL: your.email@example.com/  LETSENCRYPT_ACCOUNT_EMAIL: $letsencrypt_account_email/w $changelog" $config_file
+    SLASH="BROKEN"
+    echo "========================================"
+    echo "WARNING!!!"
+    echo "Your password contains a quote (\")"
+    echo "Your SMTP Password will not be set. You will need to edit app.yml to enter it."
+    echo "========================================"
+    update_ok="n"
+  else
+    SLASH="|"
+    if [[ "$smtp_password" == *"$SLASH"* ]]
+    then SLASH="+"
+      if [[ "$smtp_password" == *"$SLASH"* ]]
+      then
+        SLASH="Q"
+        if [[ "$smtp_password" == *"$SLASH"* ]]
+       then
+         SLASH="BROKEN"
+          echo "========================================"
+          echo "WARNING!!!"
+          echo "Your password contains all available delimiters (+, |, and Q). "
+          echo "Your SMTP Password will not be set. You will need to edit app.yml to enter it."
+          echo "========================================"
+          update_ok="n"
+         fi
+       fi
+    fi
+  fi
+  if [[ "$SLASH" != "BROKEN" ]]
+  then
+    sed -i -e "s${SLASH}^  #\?DISCOURSE_SMTP_PASSWORD:.*${SLASH}  DISCOURSE_SMTP_PASSWORD: \"${smtp_password}\"${SLASH}w $changelog" $web_file
+
+    if [ -s $changelog ]
+    then
+      rm $changelog
+    else
+      echo "DISCOURSE_SMTP_PASSWORD change failed."
+      update_ok="n"
+    fi
+  fi
+  if [ "$letsencrypt_status" = "ENTER to skip" ]
+  then
+      local src='^  #\?- "templates\/web.ssl.template.yml"'
+      local dst='  #\- "templates\/web.ssl.template.yml"'
+      sed -i -e "s/$src/$dst/w $changelog" $web_file
+      if [ ! -s $changelog ]
+      then
+        update_ok="n"
+        echo "web.ssl.template.yml NOT DISABLED--Are you using a non-standard template?"
+      fi
+      local src='^  #\?- "templates\/web.letsencrypt.ssl.template.yml"'
+      local dst='  #- "templates\/web.letsencrypt.ssl.template.yml"'
+
+      sed -i -e "s/$src/$dst/w $changelog" $web_file
+      if [ ! -s $changelog ]
+      then
+        update_ok="n"
+        echo "web.ssl.template.yml NOT DISABLED--Are you using a non-standard template?"
+      fi
+  else # enable let's encrypt
+    echo "Let's Encrypt will be enabled for $letsencrypt_account_email"
+      sed -i -e "s/^  #\?LETSENCRYPT_ACCOUNT_EMAIL:.*/  LETSENCRYPT_ACCOUNT_EMAIL: $letsencrypt_account_email/w $changelog" $web_file
       if [ -s $changelog ]
       then
         rm $changelog
@@ -286,20 +563,20 @@ set_config() {
         echo "LETSENCRYPT_ACCOUNT_EMAIL change failed."
         update_ok="n"
       fi
-      local src='^  #- "templates\/web.ssl.template.yml"'
+      local src='^  #\?- "templates\/web.ssl.template.yml"'
       local dst='  \- "templates\/web.ssl.template.yml"'
-      sed -i -e "s/$src/$dst/w $changelog" $config_file
+      sed -i -e "s/$src/$dst/w $changelog" $web_file
       if [ -s $changelog ]
       then
-             echo "web.ssl.template.yml enabled"
+         echo "web.ssl.template.yml enabled"
       else
         update_ok="n"
         echo "web.ssl.template.yml NOT ENABLED--was it on already?"
       fi
-      local src='^  #- "templates\/web.letsencrypt.ssl.template.yml"'
+      local src='^  #\?- "templates\/web.letsencrypt.ssl.template.yml"'
       local dst='  - "templates\/web.letsencrypt.ssl.template.yml"'
 
-      sed -i -e "s/$src/$dst/w $changelog" $config_file
+      sed -i -e "s/$src/$dst/w $changelog" $web_file
       if [ -s $changelog ]
       then
              echo "letsencrypt.ssl.template.yml enabled"
@@ -307,13 +584,14 @@ set_config() {
         update_ok="n"
         echo "letsencrypt.ssl.template.yml NOT ENABLED -- was it on already?"
       fi
-  fi 
+  fi
 
   if [ "$update_ok" == "y" ]
   then
     echo -e "\nConfiguration file at $config_file updated successfully!\n"
   else
     echo -e "\nUnfortunately, there was an error changing $config_file\n"
+    echo -d "This may happen if you have made unexpected changes."
     exit 1
   fi
 }
@@ -321,28 +599,29 @@ set_config() {
 ##
 ## is our config file valid? Does it have the required fields set?
 ##
-valid_config_check() {
+validate_config() {
 
   valid_config="y"
-  
+
   for x in DISCOURSE_SMTP_ADDRESS DISCOURSE_SMTP_USER_NAME DISCOURSE_SMTP_PASSWORD \
            DISCOURSE_DEVELOPER_EMAILS DISCOURSE_HOSTNAME
   do
-    config_line=`grep "^  $x:" $config_file` 
-    local result=$?
-    local default="example.com"
+    read_config $x
+    local result=$read_config_result
+    read_default $x
+    local default=$read_default_result
 
-    if (( result == 0 ))
+    if [ ! -z "$result" ]
     then
-      if [[ $config_line = *"$default"* ]]
+      if [[ "$config_line" = *"$default"* ]]
       then
-        echo "$x left at incorrect default of example.com"
+        echo "$x left at incorrect default of $default"
         valid_config="n"
       fi
       config_val=`echo $config_line | awk '{print $2}'`
       if [ -z $config_val ]
       then
-        echo "$x was left blank"
+        echo "$x was not configured"
         valid_config="n"
       fi
     else
@@ -350,9 +629,11 @@ valid_config_check() {
       valid_config="n"
     fi
   done
-  
+
   if [ "$valid_config" != "y" ]; then
-    echo -e "\nSorry, these $config_file settings aren't valid -- can't continue!"
+    echo -e "\nSorry, these $web_file settings aren't valid -- can't continue!"
+    echo "If you have unusual requirements, edit $web_file and then: "
+    echo "./launcher bootstrap $app_name"
     exit 1
   fi
 }
@@ -361,28 +642,94 @@ valid_config_check() {
 ##
 ## template file names
 ##
-app_name=app
-template_path=samples/standalone.yml
-config_file=containers/$app_name.yml
-changelog=/tmp/changelog
-
-## make a copy of the simple standalone config file
 
-if [ -a $config_file ]
+if [ "$1" == "2container" ]
 then
-  echo "The configuration file $config_file already exists!"
-  echo ""
-  echo "If you want to delete your old configuration file and start over:"
-  echo "rm $config_file"
-  exit 1
+    app_name=web_only
+    data_name=data
+    web_template=samples/web_only.yml
+    data_template=samples/data.yml
+    web_file=containers/$app_name.yml
+    data_file=containers/$data_name.yml
 else
-  cp $template_path $config_file
+  app_name=app
+  data_name=app
+  web_template=samples/standalone.yml
+  data_template=""
+  web_file=containers/$app_name.yml
+  data_file=containers/$app_name.yml
 fi
+    changelog=/tmp/changelog
 
+##
+## Check requirements before creating a copy of a config file we won't edit
+##
+check_root
+check_and_install_docker
 check_disk_and_memory
-check_ports
+
+if [ -a "$web_file" ]
+then
+  echo "The configuration file $web_file already exists!"
+  echo
+  echo ". . . reconfiguring . . ."
+  echo
+  echo
+  DATE=`date +"%Y-%m-%d-%H%M%S"`
+  BACKUP=$app_name.yml.$DATE.bak
+  echo Saving old file as $BACKUP
+  cp $web_file containers/$BACKUP
+  echo "Stopping existing container in 5 seconds or Control-C to cancel."
+  sleep 5
+  ./launcher stop app
+  echo
+else
+  check_ports
+  cp -v $web_template $web_file
+  if [ "$data_name" == "data" ]
+  then
+      echo "--------------------------------------------------"
+      echo "This two container setup is currently unsupported. Use at your own risk!"
+      echo "--------------------------------------------------"
+      DISCOURSE_DB_PASSWORD=`date +%s | sha256sum | base64 | head -c 20`
+
+     sed -i -e "s/DISCOURSE_DB_PASSWORD: SOME_SECRET/DISCOURSE_DB_PASSWORD: $DISCOURSE_DB_PASSWORD/w $changelog" $web_file
+     if  [ -s $changelog ]
+     then
+        rm $changelog
+     else
+       echo "Problem changing DISCOURSE_DB_PASSWORD" in $web_file
+     fi
+
+     cp -v $data_template $data_file
+     quote=\'
+     sed -i -e "s/password ${quote}SOME_SECRET${quote}/password '$DISCOURSE_DB_PASSWORD'/w $changelog" $data_file
+     if  [ -s $changelog ]
+     then
+        rm $changelog
+     else
+       echo "Problem changing DISCOURSE_DB_PASSWORD" in $data_file
+     fi
+  fi
+fi
+
 scale_ram_and_cpu
-set_config
-valid_config_check
+ask_user_for_config
+validate_config
 
-./launcher bootstrap $app_name
+##
+## if we reach this point without exiting, OK to proceed
+## rebuild won't fail if there's nothing to rebuild and does the restart
+##
+echo "Updates successful. Rebuilding in 5 seconds."
+sleep 5 # Just a chance to ^C in case they were too fast on the draw
+if [ "$data_name" == "$app_name" ]
+then
+    echo Building $app_name
+    ./launcher rebuild $app_name
+else
+    echo Building $data_name now . . .
+    ./launcher rebuild $data_name
+    echo Building $app_name now . . .
+    ./launcher rebuild $app_name
+fi