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" $data_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" $web_file
227 echo "setting UNICORN_WORKERS = ${unicorn_workers}"
231 echo $data_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 "This will show you what command is using port ${1}"
256 lsof
-i tcp
:${1} -s tcp
:listen
258 echo "If you are trying to run Discourse simultaneously with another web"
259 echo "server like Apache or nginx, you will need to bind to a different port"
261 echo "See https://meta.discourse.org/t/17247"
263 echo "If you are reconfiguring an already-configured Discourse, use "
265 echo "./launcher stop app"
267 echo "to stop Discourse before you reconfigure it and try again."
273 ## read a variable from the config file
276 config_line
=`egrep "^ #?$1:" $web_file`
277 read_config_result
=`echo $config_line | awk '{print $2}'`
278 read_config_result
=`echo $read_config_result | sed "s/^\([\"']\)\(.*\)\1\$/\2/g"`
284 ## prompt user for typical Discourse config file values
286 ask_user_for_config
() {
288 # NOTE: Defaults now come from standalone.yml
290 local changelog
=/tmp
/changelog.
$PPID
291 read_config
"DISCOURSE_SMTP_ADDRESS"
292 local smtp_address
=$read_config_result
293 # NOTE: if there are spaces between emails, this breaks, but a human should be paying attention
294 read_config
"DISCOURSE_DEVELOPER_EMAILS"
295 local developer_emails
=$read_config_result
296 read_config
"DISCOURSE_SMTP_PASSWORD"
297 local smtp_password
=$read_config_result
298 read_config
"DISCOURSE_SMTP_PORT"
299 local smtp_port
=$read_config_result
300 read_config
"DISCOURSE_SMTP_USER_NAME"
301 local smtp_user_name
=$read_config_result
302 if [ "$smtp_password" = "pa$$word" ]
306 read_config
"LETSENCRYPT_ACCOUNT_EMAIL"
307 local letsencrypt_account_email
=$read_config_result
308 if [ -z $letsencrypt_account_email ]
310 letsencrypt_account_email
="me@example.com"
312 if [ "$letsencrypt_account_email" = "me@example.com" ]
314 local letsencrypt_status
="ENTER to skip"
316 local letsencrypt_status
="Enter 'OFF' to disable."
319 read_config
"DISCOURSE_HOSTNAME"
320 hostname
=$read_config_result
328 while [[ "$config_ok" == "n" ]]
330 if [ ! -z $hostname ]
332 read -p "Hostname for your Discourse? [$hostname]: " new_value
333 if [ ! -z $new_value ]
339 if [ ! -z $developer_emails ]
341 read -p "Email address for admin account(s)? [$developer_emails]: " new_value
342 if [ ! -z $new_value ]
344 developer_emails
=$new_value
348 if [ ! -z $smtp_address ]
350 read -p "SMTP server address? [$smtp_address]: " new_value
351 if [ ! -z $new_value ]
353 smtp_address
=$new_value
357 if [ ! -z $smtp_port ]
359 read -p "SMTP port? [$smtp_port]: " new_value
360 if [ ! -z $new_value ]
367 ## automatically set correct user name based on common mail providers
369 if [ "$smtp_address" == "smtp.sparkpostmail.com" ]
371 smtp_user_name
="SMTP_Injection"
373 if [ "$smtp_address" == "smtp.sendgrid.net" ]
375 smtp_user_name
="apikey"
377 if [ "$smtp_address" == "smtp.mailgun.org" ]
379 smtp_user_name
="postmaster@$hostname"
382 if [ ! -z $smtp_user_name ]
384 read -p "SMTP user name? [$smtp_user_name]: " new_value
385 if [ ! -z "$new_value" ]
387 smtp_user_name
="$new_value"
391 read -p "SMTP password? [$smtp_password]: " new_value
392 if [ ! -z $new_value ]
394 smtp_password
=$new_value
397 if [ ! -z $letsencrypt_account_email ]
399 read -p "Let's Encrypt account email? ($letsencrypt_status) [$letsencrypt_account_email]: " new_value
400 if [ ! -z $new_value ]
402 letsencrypt_account_email
=$new_value
403 if [ "${new_value,,}" = "off" ]
405 letsencrypt_status
="ENTER to skip"
407 letsencrypt_status
="Enter 'OFF' to disable."
412 if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
414 check_IP_match
$hostname
417 echo -e "\nDoes this look right?\n"
418 echo "Hostname : $hostname"
419 echo "Email : $developer_emails"
420 echo "SMTP address : $smtp_address"
421 echo "SMTP port : $smtp_port"
422 echo "SMTP username : $smtp_user_name"
423 echo "SMTP password : $smtp_password"
425 if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
427 echo "Let's Encrypt : $letsencrypt_account_email"
432 read -p "ENTER to continue, 'n' to try again, Ctrl+C to exit: " config_ok
435 sed -i -e "s/^ DISCOURSE_HOSTNAME:.*/ DISCOURSE_HOSTNAME: $hostname/w $changelog" $web_file
440 echo "DISCOURSE_HOSTNAME change failed."
444 sed -i -e "s/^ DISCOURSE_DEVELOPER_EMAILS:.*/ DISCOURSE_DEVELOPER_EMAILS: \'$developer_emails\'/w $changelog" $web_file
449 echo "DISCOURSE_DEVELOPER_EMAILS change failed."
453 sed -i -e "s/^ DISCOURSE_SMTP_ADDRESS:.*/ DISCOURSE_SMTP_ADDRESS: $smtp_address/w $changelog" $web_file
458 echo "DISCOURSE_SMTP_ADDRESS change failed."
462 sed -i -e "s/^ #\?DISCOURSE_SMTP_PORT:.*/ DISCOURSE_SMTP_PORT: $smtp_port/w $changelog" $web_file
467 echo "DISCOURSE_SMTP_PORT change failed."
471 sed -i -e "s/^ #\?DISCOURSE_SMTP_USER_NAME:.*/ DISCOURSE_SMTP_USER_NAME: $smtp_user_name/w $changelog" $web_file
476 echo "DISCOURSE_SMTP_USER_NAME change failed."
480 sed -i -e "s/^ #\?DISCOURSE_SMTP_PASSWORD:.*/ DISCOURSE_SMTP_PASSWORD: \"${smtp_password/\//\\/}\"/w $changelog" $web_file
485 echo "DISCOURSE_SMTP_PASSWORD change failed."
489 if [ "$letsencrypt_status" = "ENTER to skip" ]
491 local src
='^ #\?- "templates\/web.ssl.template.yml"'
492 local dst
=' #\- "templates\/web.ssl.template.yml"'
493 sed -i -e "s/$src/$dst/w $changelog" $web_file
494 if [ ! -s $changelog ]
497 echo "web.ssl.template.yml NOT DISABLED--Are you using a non-standard template?"
499 local src
='^ #\?- "templates\/web.letsencrypt.ssl.template.yml"'
500 local dst
=' #- "templates\/web.letsencrypt.ssl.template.yml"'
502 sed -i -e "s/$src/$dst/w $changelog" $web_file
503 if [ ! -s $changelog ]
506 echo "web.ssl.template.yml NOT DISABLED--Are you using a non-standard template?"
508 else # enable let's encrypt
509 echo "Let's Encrypt will be enabled for $letsencrypt_account_email"
510 sed -i -e "s/^ #\?LETSENCRYPT_ACCOUNT_EMAIL:.*/ LETSENCRYPT_ACCOUNT_EMAIL: $letsencrypt_account_email/w $changelog" $web_file
515 echo "LETSENCRYPT_ACCOUNT_EMAIL change failed."
518 local src
='^ #\?- "templates\/web.ssl.template.yml"'
519 local dst
=' \- "templates\/web.ssl.template.yml"'
520 sed -i -e "s/$src/$dst/w $changelog" $web_file
523 echo "web.ssl.template.yml enabled"
526 echo "web.ssl.template.yml NOT ENABLED--was it on already?"
528 local src
='^ #\?- "templates\/web.letsencrypt.ssl.template.yml"'
529 local dst
=' - "templates\/web.letsencrypt.ssl.template.yml"'
531 sed -i -e "s/$src/$dst/w $changelog" $web_file
534 echo "letsencrypt.ssl.template.yml enabled"
537 echo "letsencrypt.ssl.template.yml NOT ENABLED -- was it on already?"
541 if [ "$update_ok" == "y" ]
543 echo -e "\nConfiguration file at $config_file updated successfully!\n"
545 echo -e "\nUnfortunately, there was an error changing $config_file\n"
546 echo -d "This may happen if you have made unexpected changes."
552 ## is our config file valid? Does it have the required fields set?
558 for x
in DISCOURSE_SMTP_ADDRESS DISCOURSE_SMTP_USER_NAME DISCOURSE_SMTP_PASSWORD \
559 DISCOURSE_DEVELOPER_EMAILS DISCOURSE_HOSTNAME
561 config_line
=`grep "^ $x:" $web_file`
563 local default
="example.com"
567 if [[ "$config_line" = *"$default"* ]]
569 echo "$x left at incorrect default of example.com"
572 config_val
=`echo $config_line | awk '{print $2}'`
573 if [ -z $config_val ]
575 echo "$x was left blank"
579 echo "$x not present"
584 if [ "$valid_config" != "y" ]; then
585 echo -e "\nSorry, these $web_file settings aren't valid -- can't continue!"
586 echo "If you have unusual requirements, edit $web_file and then: "
587 echo "./launcher bootstrap $app_name"
594 ## template file names
597 if [ "$1" == "2container" ]
601 web_template
=samples
/web_only.yml
602 data_template
=samples
/data.yml
603 web_file
=containers
/$app_name.yml
604 data_file
=containers
/$data_name.yml
608 web_template
=samples
/standalone.yml
610 web_file
=containers
/$app_name.yml
611 data_file
=containers
/$app_name.yml
613 changelog
=/tmp
/changelog
616 ## Check requirements before creating a copy of a config file we won't edit
619 check_and_install_docker
620 check_disk_and_memory
622 if [ -a "$web_file" ]
624 echo "The configuration file $web_file already exists!"
626 echo ". . . reconfiguring . . ."
629 DATE
=`date +"%Y-%m-%d-%H%M%S"`
630 BACKUP
=$app_name.yml.
$DATE.bak
631 echo Saving old
file as
$BACKUP
632 cp $config_file containers
/$BACKUP
633 echo "Stopping existing container in 5 seconds or Control-C to cancel."
639 cp -v $web_template $web_file
640 if [ "$data_name" == "data" ]
642 echo "--------------------------------------------------"
643 echo "This multisite setup is currently unsupported. Use at your own risk!"
644 echo "--------------------------------------------------"
645 DISCOURSE_DB_PASSWORD
=`date +%s | sha256sum | base64 | head -c 20`
647 sed -i -e "s/DISCOURSE_DB_PASSWORD: SOME_SECRET/DISCOURSE_DB_PASSWORD: $DISCOURSE_DB_PASSWORD/w $changelog" $web_file
652 echo "Problem changing DISCOURSE_DB_PASSWORD" in $web_file
655 cp -v $data_template $data_file
657 sed -i -e "s/password ${quote}SOME_SECRET${quote}/password '$DISCOURSE_DB_PASSWORD'/w $changelog" $data_file
662 echo "Problem changing DISCOURSE_DB_PASSWORD" in $data_file
672 ## if we reach this point without exiting, OK to proceed
673 ## rebuild won't fail if there's nothing to rebuild and does the restart
675 echo "Updates successful. Rebuilding in 5 seconds."
676 sleep 5 # Just a chance to ^C in case they were too fast on the draw
677 if [ "$data_name" == "$app_name" ]
679 echo Building
$app_name
680 .
/launcher rebuild
$app_name
682 echo Building
$data_name now . . .
683 .
/launcher rebuild
$data_name
684 echo Building
$app_name now . . .
685 .
/launcher rebuild
$app_name