4 ## Make sure only root can run our script
7 if [[ $EUID -ne 0 ]]; then
8 echo "This script must be run as root. Please sudo or log in as root first." 1>&2
14 ## Check whether a connection to HOSTNAME ($1) on PORT ($2) is possible
19 VERIFY
=`date +%s | sha256sum | base64 | head -c 20`
20 echo -e "HTTP/1.1 200 OK\n\n $VERIFY" | nc
-w 4 -l -p $PORT >/dev
/null
2>&1 &
21 if curl
--proto =http
-s $HOST:$PORT --connect-timeout 3 |
grep $VERIFY >/dev
/null
2>&1
25 curl
--proto =http
-s localhost
:$PORT >/dev
/null
2>&1
33 echo Checking your domain name . . .
34 if connect_to_port
$HOST 443
37 echo "Connection to $HOST succeeded."
39 echo WARNING
:: This server does not appear to be accessible
at $HOST:443.
41 if connect_to_port
$HOST 80
43 echo A connection to port
80 succeeds
, however.
44 echo This suggests that your DNS settings are correct
,
45 echo but something is keeping traffic to port
443 from getting to your server.
46 echo Check your networking configuration to see that connections to port
443 are allowed.
48 echo "A connection to http://$HOST (port 80) also fails."
50 echo This suggests that
$HOST resolves to the wrong IP address
51 echo or that traffic is not being routed to your server.
54 echo Google
: \"open ports YOUR CLOUD SERVICE
\" for information
for resolving this problem.
56 echo You should probably answer
\"n
\" at the next prompt and disable Let
\'s Encrypt.
58 echo This
test might not work
for all situations
,
59 echo so
if you can access Discourse
at http
://$HOST, you might try anyway.
67 check_and_install_docker
() {
68 docker_path
=`which docker.io || which docker`
69 if [ -z $docker_path ]; then
70 read -p "Docker not installed. Enter to install from https://get.docker.com/ or Ctrl+C to exit"
71 curl https
://get.docker.com
/ | sh
73 docker_path
=`which docker.io || which docker`
74 if [ -z $docker_path ]; then
75 echo Docker
install failed. Quitting.
81 ## What are we running on
88 ## OS X available memory
91 echo `top -l 1 | awk '/PhysMem:/ {print $2}' | sed s/G//`
95 ## Linux available memory
97 check_linux_memory
() {
98 echo `free -g --si | awk ' /Mem:/ {print $2} '`
102 ## Do we have enough memory and disk space for Discourse?
104 check_disk_and_memory
() {
108 if [ "$os_type" == "Darwin" ]; then
109 avail_mem
=$
(check_osx_memory
)
111 avail_mem
=$
(check_linux_memory
)
114 if [ "$avail_mem" -lt 1 ]; then
115 echo "WARNING: Discourse requires 1GB RAM to run. This system does not appear"
116 echo "to have sufficient memory."
118 echo "Your site may not work properly, or future upgrades of Discourse may not"
119 echo "complete successfully."
123 if [ "$avail_mem" -le 2 ]; then
124 total_swap
=`free -g --si | awk ' /Swap:/ {print $2} '`
126 if [ "$total_swap" -lt 2 ]; then
127 echo "WARNING: Discourse requires at least 2GB of swap when running with 2GB of RAM"
128 echo "or less. This system does not appear to have sufficient swap space."
130 echo "Without sufficient swap space, your site may not work properly, and future"
131 echo "upgrades of Discourse may not complete successfully."
133 echo "Ctrl+C to exit or wait 5 seconds to have a 2GB swapfile created."
137 ## derived from https://meta.discourse.org/t/13880
139 install -o root
-g root
-m 0600 /dev
/null
/swapfile
140 dd if=/dev
/zero of
=/swapfile bs
=1k count
=2048k
143 echo "/swapfile swap swap auto 0 0" |
tee -a /etc
/fstab
144 sysctl
-w vm.swappiness
=10
145 echo vm.swappiness
= 10 |
tee -a /etc
/sysctl.conf
147 total_swap
=`free -g --si | awk ' /Swap:/ {print $2} '`
148 if [ "$total_swap" -lt 2 ]; then
149 echo "Failed to create swap, sorry!"
157 free_disk
="$(df /var | tail -n 1 | awk '{print $4}')"
158 if [ "$free_disk" -lt 5000 ]; then
159 echo "WARNING: Discourse requires at least 5GB free disk space. This system"
160 echo "does not appear to have sufficient disk space."
162 echo "Insufficient disk space may result in problems running your site, and"
163 echo "may not even allow Discourse installation to complete successfully."
165 echo "Please free up some space, or expand your disk, before continuing."
167 echo "Run \`apt-get autoremove && apt-get autoclean\` to clean up unused"
168 echo "packages and \`./launcher cleanup\` to remove stale Docker containers."
176 ## If we have lots of RAM or lots of CPUs, bump up the defaults to scale better
178 scale_ram_and_cpu
() {
180 local changelog
=/tmp
/changelog.
$PPID
181 # grab info about total system ram and physical (NOT LOGICAL!) CPU cores
185 if [ "$os_type" == "Darwin" ]; then
186 avail_gb
=$
(check_osx_memory
)
187 avail_cores
=`sysctl hw.ncpu | awk '/hw.ncpu:/ {print $2}'`
189 avail_gb
=$
(check_linux_memory
)
190 avail_cores
=$
((`awk '/cpu cores/ {print $4;exit}' /proc/cpuinfo`*`sort /proc/cpuinfo | uniq | grep -c "physical id"`))
192 echo "Found ${avail_gb}GB of memory and $avail_cores physical CPU cores"
194 # db_shared_buffers: 128MB for 1GB, 256MB for 2GB, or 256MB * GB, max 4096MB
195 if [ "$avail_gb" -eq "1" ]
197 db_shared_buffers
=128
199 if [ "$avail_gb" -eq "2" ]
201 db_shared_buffers
=256
203 db_shared_buffers
=$
(( 256 * $avail_gb ))
206 db_shared_buffers
=$
(( db_shared_buffers
< 4096 ? db_shared_buffers
: 4096 ))
208 sed -i -e "s/^ #\?db_shared_buffers:.*/ db_shared_buffers: \"${db_shared_buffers}MB\"/w $changelog" $config_file
211 echo "setting db_shared_buffers = ${db_shared_buffers}MB"
215 # UNICORN_WORKERS: 2 * GB for 2GB or less, or 2 * CPU, max 8
216 if [ "$avail_gb" -le "2" ]
218 unicorn_workers
=$
(( 2 * $avail_gb ))
220 unicorn_workers
=$
(( 2 * $avail_cores ))
222 unicorn_workers
=$
(( unicorn_workers
< 8 ? unicorn_workers
: 8 ))
224 sed -i -e "s/^ #\?UNICORN_WORKERS:.*/ UNICORN_WORKERS: ${unicorn_workers}/w $changelog" $config_file
227 echo "setting UNICORN_WORKERS = ${unicorn_workers}"
231 echo $config_file memory parameters updated.
236 ## standard http / https ports must not be occupied
241 echo "Ports 80 and 443 are free for use"
246 ## check a port to see if it is already in use
250 local valid
=$
(netstat
-tln |
awk '{print $4}' |
grep ":${1}\$")
252 if [ -n "$valid" ]; then
253 echo "Port ${1} appears to already be in use."
255 echo "If you are trying to run Discourse simultaneously with another web"
256 echo "server like Apache or nginx, you will need to bind to a different port"
258 echo "See https://meta.discourse.org/t/17247"
260 echo "If you are reconfiguring an already-configured Discourse, use "
262 echo "./launcher stop app"
264 echo "to stop Discourse before you reconfigure it and try again."
270 ## read a variable from the config file
274 config_line
=`egrep "^ #?$1:" $config_file`
275 read_config_result
=`echo $config_line | awk '{print $2}'`
276 read_config_result
=`echo $read_config_result | sed "s/^\([\"']\)\(.*\)\1\$/\2/g"`
282 ## prompt user for typical Discourse config file values
284 ask_user_for_config
() {
286 # NOTE: Defaults now come from standalone.yml
288 local changelog
=/tmp
/changelog.
$PPID
289 read_config
"DISCOURSE_SMTP_ADDRESS"
290 local smtp_address
=$read_config_result
291 # NOTE: if there are spaces between emails, this breaks, but a human should be paying attention
292 read_config
"DISCOURSE_DEVELOPER_EMAILS"
293 local developer_emails
=$read_config_result
294 read_config
"DISCOURSE_SMTP_PASSWORD"
295 local smtp_password
=$read_config_result
296 read_config
"DISCOURSE_SMTP_PORT"
297 local smtp_port
=$read_config_result
298 read_config
"DISCOURSE_SMTP_USER_NAME"
299 local smtp_user_name
=$read_config_result
300 if [ "$smtp_password" = "pa$$word" ]
304 read_config
"LETSENCRYPT_ACCOUNT_EMAIL"
305 local letsencrypt_account_email
=$read_config_result
306 if [ -z $letsencrypt_account_email ]
308 letsencrypt_account_email
="me@example.com"
310 if [ "$letsencrypt_account_email" = "me@example.com" ]
312 local letsencrypt_status
="ENTER to skip"
314 local letsencrypt_status
="Enter 'OFF' to disable."
317 read_config
"DISCOURSE_HOSTNAME"
318 hostname
=$read_config_result
326 while [[ "$config_ok" == "n" ]]
328 if [ ! -z $hostname ]
330 read -p "Hostname for your Discourse? [$hostname]: " new_value
331 if [ ! -z $new_value ]
337 if [ ! -z $developer_emails ]
339 read -p "Email address for admin account(s)? [$developer_emails]: " new_value
340 if [ ! -z $new_value ]
342 developer_emails
=$new_value
346 if [ ! -z $smtp_address ]
348 read -p "SMTP server address? [$smtp_address]: " new_value
349 if [ ! -z $new_value ]
351 smtp_address
=$new_value
355 if [ ! -z $smtp_port ]
357 read -p "SMTP port? [$smtp_port]: " new_value
358 if [ ! -z $new_value ]
365 ## automatically set correct user name based on common mail providers
367 if [ "$smtp_address" == "smtp.sparkpostmail.com" ]
369 smtp_user_name
="SMTP_Injection"
371 if [ "$smtp_address" == "smtp.sendgrid.net" ]
373 smtp_user_name
="apikey"
375 if [ "$smtp_address" == "smtp.mailgun.org" ]
377 smtp_user_name
="postmaster@$hostname"
380 if [ ! -z $smtp_user_name ]
382 read -p "SMTP user name? [$smtp_user_name]: " new_value
383 if [ ! -z "$new_value" ]
385 smtp_user_name
="$new_value"
389 read -p "SMTP password? [$smtp_password]: " new_value
390 if [ ! -z $new_value ]
392 smtp_password
=$new_value
395 if [ ! -z $letsencrypt_account_email ]
397 read -p "Let's Encrypt account email? ($letsencrypt_status) [$letsencrypt_account_email]: " new_value
398 if [ ! -z $new_value ]
400 letsencrypt_account_email
=$new_value
401 if [ "${new_value,,}" = "off" ]
403 letsencrypt_status
="ENTER to skip"
405 letsencrypt_status
="Enter 'OFF' to disable."
410 if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
412 check_IP_match
$hostname
415 echo -e "\nDoes this look right?\n"
416 echo "Hostname : $hostname"
417 echo "Email : $developer_emails"
418 echo "SMTP address : $smtp_address"
419 echo "SMTP port : $smtp_port"
420 echo "SMTP username : $smtp_user_name"
421 echo "SMTP password : $smtp_password"
423 if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
425 echo "Let's Encrypt : $letsencrypt_account_email"
430 read -p "ENTER to continue, 'n' to try again, Ctrl+C to exit: " config_ok
433 sed -i -e "s/^ DISCOURSE_HOSTNAME:.*/ DISCOURSE_HOSTNAME: $hostname/w $changelog" $config_file
438 echo "DISCOURSE_HOSTNAME change failed."
442 sed -i -e "s/^ DISCOURSE_DEVELOPER_EMAILS:.*/ DISCOURSE_DEVELOPER_EMAILS: \'$developer_emails\'/w $changelog" $config_file
447 echo "DISCOURSE_DEVELOPER_EMAILS change failed."
451 sed -i -e "s/^ DISCOURSE_SMTP_ADDRESS:.*/ DISCOURSE_SMTP_ADDRESS: $smtp_address/w $changelog" $config_file
456 echo "DISCOURSE_SMTP_ADDRESS change failed."
460 sed -i -e "s/^ #\?DISCOURSE_SMTP_PORT:.*/ DISCOURSE_SMTP_PORT: $smtp_port/w $changelog" $config_file
465 echo "DISCOURSE_SMTP_PORT change failed."
469 sed -i -e "s/^ #\?DISCOURSE_SMTP_USER_NAME:.*/ DISCOURSE_SMTP_USER_NAME: $smtp_user_name/w $changelog" $config_file
474 echo "DISCOURSE_SMTP_USER_NAME change failed."
478 sed -i -e "s/^ #\?DISCOURSE_SMTP_PASSWORD:.*/ DISCOURSE_SMTP_PASSWORD: \"${smtp_password/\//\\/}\"/w $changelog" $config_file
483 echo "DISCOURSE_SMTP_PASSWORD change failed."
487 if [ "$letsencrypt_status" = "ENTER to skip" ]
489 local src
='^ #\?- "templates\/web.ssl.template.yml"'
490 local dst
=' #\- "templates\/web.ssl.template.yml"'
491 sed -i -e "s/$src/$dst/w $changelog" $config_file
492 if [ ! -s $changelog ]
495 echo "web.ssl.template.yml NOT DISABLED--Are you using a non-standard template?"
497 local src
='^ #\?- "templates\/web.letsencrypt.ssl.template.yml"'
498 local dst
=' #- "templates\/web.letsencrypt.ssl.template.yml"'
500 sed -i -e "s/$src/$dst/w $changelog" $config_file
501 if [ ! -s $changelog ]
504 echo "web.ssl.template.yml NOT DISABLED--Are you using a non-standard template?"
506 else # enable let's encrypt
507 echo "Let's Encrypt will be enabled for $letsencrypt_account_email"
508 sed -i -e "s/^ #\?LETSENCRYPT_ACCOUNT_EMAIL:.*/ LETSENCRYPT_ACCOUNT_EMAIL: $letsencrypt_account_email/w $changelog" $config_file
513 echo "LETSENCRYPT_ACCOUNT_EMAIL change failed."
516 local src
='^ #\?- "templates\/web.ssl.template.yml"'
517 local dst
=' \- "templates\/web.ssl.template.yml"'
518 sed -i -e "s/$src/$dst/w $changelog" $config_file
521 echo "web.ssl.template.yml enabled"
524 echo "web.ssl.template.yml NOT ENABLED--was it on already?"
526 local src
='^ #\?- "templates\/web.letsencrypt.ssl.template.yml"'
527 local dst
=' - "templates\/web.letsencrypt.ssl.template.yml"'
529 sed -i -e "s/$src/$dst/w $changelog" $config_file
532 echo "letsencrypt.ssl.template.yml enabled"
535 echo "letsencrypt.ssl.template.yml NOT ENABLED -- was it on already?"
539 if [ "$update_ok" == "y" ]
541 echo -e "\nConfiguration file at $config_file updated successfully!\n"
543 echo -e "\nUnfortunately, there was an error changing $config_file\n"
544 echo -d "This may happen if you have made unexpected changes."
550 ## is our config file valid? Does it have the required fields set?
556 for x
in DISCOURSE_SMTP_ADDRESS DISCOURSE_SMTP_USER_NAME DISCOURSE_SMTP_PASSWORD \
557 DISCOURSE_DEVELOPER_EMAILS DISCOURSE_HOSTNAME
559 config_line
=`grep "^ $x:" $config_file`
561 local default
="example.com"
565 if [[ "$config_line" = *"$default"* ]]
567 echo "$x left at incorrect default of example.com"
570 config_val
=`echo $config_line | awk '{print $2}'`
571 if [ -z $config_val ]
573 echo "$x was left blank"
577 echo "$x not present"
582 if [ "$valid_config" != "y" ]; then
583 echo -e "\nSorry, these $config_file settings aren't valid -- can't continue!"
584 echo "If you have unusual requirements, edit $config_file and then: "
585 echo "./launcher bootstrap $app_name"
592 ## template file names
595 template_path
=samples
/standalone.yml
596 config_file
=containers
/$app_name.yml
597 changelog
=/tmp
/changelog
600 ## Check requirements before creating a copy of a config file we won't edit
603 check_and_install_docker
604 check_disk_and_memory
607 ## make a copy of the simple standalone config file
609 if [ -a $config_file ]
611 echo "The configuration file $config_file already exists."
613 echo ". . . reconfiguring . . ."
616 DATE
=`date +"%Y-%m-%d-%H%M%S"`
617 BACKUP
=$app_name.yml.
$DATE.bak
618 echo Saving old
file as
$BACKUP
619 cp $config_file containers
/$BACKUP
620 echo "Stopping existing container in 5 seconds or Control-C to cancel."
625 check_ports
# don't need to check ports if Discourse was already installed
626 cp $template_path $config_file
634 ## if we reach this point without exiting, OK to proceed
635 ## rebuild won't fail if there's nothing to rebuild and does the restart
637 echo "Updates successful. Rebuilding in 5 seconds."
638 sleep 5 # Just a chance to ^C in case they were too fast on the draw
639 time .
/launcher rebuild
$app_name