#!/usr/bin/env bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $DIR if [ "$1" == "2container" ] then TWO_CONTAINER="1" echo "2container argument is deprecated. Use --two-container" shift 1 fi while [ ${#} -gt 0 ]; do case "${1}" in --debug) DEBUG="1" SKIP_REBUILD="1" ;; --skip-rebuild) SKIP_REBUILD="1" ;; --two-container) TWO_CONTAINER="1" ;; --skip-connection-test) SKIP_CONNECTION_TEST="1" echo "skipping connection test" ;; esac shift 1 done ## ## 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) if ! [ -x "$(command -v nc)" ]; then echo "In order to check the connection to $HOST:$PORT we need to open a socket using netcat." echo However netcat is not installed on your system. You can continue without this check echo or abort the setup, install netcat and try again. while true; do read -p "Would you like to continue without this check? [yn] " yn case $yn in [Yy]*) return 2 ;; [Nn]*) exit ;; *) echo "Please answer y or n." ;; esac done else 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 fi } check_IP_match() { HOST="$1" echo if [ "$SKIP_CONNECTION_TEST" == 1 ] then echo "Setting EC to 2" ec=2 else echo Checking your domain name . . . connect_to_port $HOST 443; ec=$? fi case $ec in 0) echo "Connection to $HOST succeeded." ;; 1) echo "WARNING: Port 443 of computer does not appear to be accessible using hostname: $HOST." if connect_to_port $HOST 80; then echo echo SUCCESS: A connection to port 80 succeeds! 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 "WARNING: Connection to http://$HOST (port 80) also fails." echo echo "This suggests that $HOST resolves to some IP address that does not reach this " echo machine where you are installing discourse. fi echo echo "The first thing to do is confirm that $HOST resolves to the IP address of this server." echo You usually do this at the same place you purchased the domain. echo echo If you are sure that the IP address resolves correctly, it could be a firewall issue. echo A web search for \"open ports YOUR CLOUD SERVICE\" might help. echo echo This tool is designed only for the most standard installations. If you cannot resolve echo the issue above, you will need to edit containers/app.yml yourself and then type echo echo ./launcher rebuild app echo exit 1 ;; 2) echo "Skipping port check." ;; esac } ## ## Do we have docker? ## check_docker() { (which docker || which docker.io) &>/dev/null } check_and_install_docker() { if ! check_docker; then echo Failed to find docker or docker.io on your PATH. read -p "Enter to install Docker from https://get.docker.com/ or Ctrl+C to exit" curl https://get.docker.com/ | sh if ! check_docker; then echo Still failed to find docker or docker.io on your PATH. echo Docker install failed. Quitting. exit fi fi } ## ## What are we running on ## check_OS() { echo `uname -s` } ## ## macOS available memory ## check_macos_memory() { echo $(($(memory_pressure | head -n 1 | awk '{ print $4 }') / 1024 / 1024 / 1024)) } ## ## Linux available memory ## check_linux_memory() { ## some VMs report just under 1GB of RAM, so ## make an exception and allow those with more ## than 989MB mem=`free -m --si | awk ' /Mem:/ {print $2}'` if [ "$mem" -ge 990 -a "$mem" -lt 1000 ]; then echo 1 else echo `free -g --si | awk ' /Mem:/ {print $2} '` fi } ## ## Do we have enough memory and disk space for Discourse? ## check_disk_and_memory() { os_type=$(check_OS) avail_mem=0 if [ "$os_type" == "Darwin" ]; then avail_mem=$(check_macos_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 "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 "Without sufficient swap space, your site may not work properly, and future" echo "upgrades of Discourse may not complete successfully." echo 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 fallocate -l 2G /swapfile 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 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" 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" echo "packages and \`./launcher cleanup\` to remove stale Docker containers." exit 1 fi } ## ## If we have lots of RAM or lots of CPUs, bump up the defaults to scale better ## scale_ram_and_cpu() { local changelog=/tmp/changelog.$PPID # grab info about total system ram and physical (NOT LOGICAL!) CPU cores avail_gb=0 avail_cores=0 os_type=$(check_OS) if [ "$os_type" == "Darwin" ]; then avail_gb=$(check_macos_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 if [ "$avail_gb" -eq "1" ] then db_shared_buffers=128 else if [ "$avail_gb" -eq "2" ] then db_shared_buffers=256 else db_shared_buffers=$(( 256 * $avail_gb )) fi 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" $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 unicorn_workers=$(( 2 * $avail_gb )) else unicorn_workers=$(( 2 * $avail_cores )) fi unicorn_workers=$(( unicorn_workers < 8 ? unicorn_workers : 8 )) 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() { check_port "80" check_port "443" echo "Ports 80 and 443 are free for use" } ## ## check a port to see if it is already in use ## check_port() { local valid=$(lsof -i:${1} | grep "LISTEN") if [ -n "$valid" ]; then echo "Port ${1} appears to already be in use." echo 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"` } assert_maxmind_license_key() { if ! grep DISCOURSE_MAXMIND_LICENSE_KEY $web_file >/dev/null 2>&1 then echo "Adding MAXMIND placeholder to $web_file" sed -i '/^.*LETSENCRYPT_ACCOUNT_EMAIL.*/a \ \ #DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456' $web_file fi if ! grep DISCOURSE_MAXMIND_LICENSE_KEY $web_file >/dev/null 2>&1 then cat </dev/null 2>&1 then echo "Adding SMTP_DOMAIN placeholder to $web_file" sed -i '/^.*DISCOURSE_SMTP_PASSWORD.*/a \ \ #DISCOURSE_SMTP_DOMAIN: discourse.example.com # (required by some providers)' $web_file fi if ! grep DISCOURSE_SMTP_DOMAIN $web_file >/dev/null 2>&1 then cat </dev/null 2>&1 then echo "Adding DISCOURSE_NOTIFICATION_EMAIL placeholder to $web_file" sed -i '/^.*DISCOURSE_SMTP_PASSWORD.*/a \ \ #DISCOURSE_NOTIFICATION_EMAIL: nobody@discourse.example.com # (address to send notifications from)' $web_file fi if ! grep DISCOURSE_NOTIFICATION_EMAIL $web_file >/dev/null 2>&1 then cat <