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
15 ## Does the current IP match the domain name?
19 echo Checking your domain name . . .
22 local IFCONFIG
=`which ifconfig`
23 /sbin
/route |
grep default
> /tmp
/route
$PPID
25 if grep default
/tmp
/route
$PPID > /dev
/null
27 local IFACE
=`cut -c 73-100 /tmp/route$PPID |head -1`
29 echo WARNING
: Cannot check your IP number.
31 local IP
=`$IFCONFIG $IFACE|grep "inet addr:" |cut -d":" -f 2|cut -d" " -f1|head -1`
32 local RESOLVED_IP
=`dig +short $1`
35 if [[ ! -z $RESOLVED_IP ]]
37 if [ "$IP" == "$RESOLVED_IP" ]
39 echo $1 resolves to
$IP. Looks good
!
44 if [ $IP_LOOKS_GOOD == 0 ]
46 echo "-----------------------------------------"
47 echo WARNING
:: $1 does not appear to resolve to
$IP.
49 echo LET
\'S ENCRYPT cannot work
if their servers cannot access your
host by name.
50 echo Unless you think you know why this naive check failed
, DO NOT USE Let
\'s Encrypt.
51 echo "(A typical reason for failure is an AWS server with an elastic IP.)"
53 echo You should probably answer
\"n
\" at the next prompt and disable Let
\'s Encrypt.
54 echo "-----------------------------------------"
62 check_and_install_docker
() {
63 docker_path
=`which docker.io || which docker`
64 if [ -z $docker_path ]; then
65 read -p "Docker not installed. Enter to install from https://get.docker.com/ or Ctrl+C to exit"
66 curl https
://get.docker.com
/ | sh
68 docker_path
=`which docker.io || which docker`
69 if [ -z $docker_path ]; then
70 echo Docker
install failed. Quitting.
76 ## What are we running on
83 ## OS X available memory
86 echo `top -l 1 | awk '/PhysMem:/ {print $2}' | sed s/G//`
90 ## Linux available memory
92 check_linux_memory
() {
93 echo `free -g --si | awk ' /Mem:/ {print $2} '`
97 ## Do we have enough memory and disk space for Discourse?
99 check_disk_and_memory
() {
103 if [ "$os_type" == "Darwin" ]; then
104 avail_mem
=$
(check_osx_memory
)
106 avail_mem
=$
(check_linux_memory
)
109 if [ "$avail_mem" -lt 1 ]; then
110 echo "WARNING: Discourse requires 1GB RAM to run. This system does not appear"
111 echo "to have sufficient memory."
113 echo "Your site may not work properly, or future upgrades of Discourse may not"
114 echo "complete successfully."
118 if [ "$avail_mem" -le 2 ]; then
119 total_swap
=`free -g --si | awk ' /Swap:/ {print $2} '`
120 if [ "$total_swap" -lt 2 ]; then
121 echo "WARNING: Discourse requires at least 2GB of swap when running with 2GB of RAM"
122 echo "or less. This system does not appear to have sufficient swap space."
124 echo "Without sufficient swap space, your site may not work properly, and future"
125 echo "upgrades of Discourse may not complete successfully."
127 read -p "ENTER to create a 2GB swapfile now, or Ctrl+C to exit"
130 ## derived from https://meta.discourse.org/t/13880
132 install -o root
-g root
-m 0600 /dev
/null
/swapfile
133 dd if=/dev
/zero of
=/swapfile bs
=1k count
=2048k
136 echo "/swapfile swap swap auto 0 0" |
tee -a /etc
/fstab
137 sysctl
-w vm.swappiness
=10
138 echo vm.swappiness
= 10 |
tee -a /etc
/sysctl.conf
140 total_swap
=`free -g --si | awk ' /Swap:/ {print $2} '`
141 if [ "$total_swap" -lt 2 ]; then
142 echo "Failed to create swap, sorry!"
150 free_disk
="$(df /var | tail -n 1 | awk '{print $4}')"
151 if [ "$free_disk" -lt 5000 ]; then
152 echo "WARNING: Discourse requires at least 5GB free disk space. This system"
153 echo "does not appear to have sufficient disk space."
155 echo "Insufficient disk space may result in problems running your site, and"
156 echo "may not even allow Discourse installation to complete successfully."
158 echo "Please free up some space, or expand your disk, before continuing."
160 echo "Run \`apt-get autoremove && apt-get autoclean\` to clean up unused"
161 echo "packages and \`./launcher cleanup\` to remove stale Docker containers."
169 ## If we have lots of RAM or lots of CPUs, bump up the defaults to scale better
171 scale_ram_and_cpu
() {
173 local changelog
=/tmp
/changelog.
$PPID
174 # grab info about total system ram and physical (NOT LOGICAL!) CPU cores
178 if [ "$os_type" == "Darwin" ]; then
179 avail_gb
=$
(check_osx_memory
)
180 avail_cores
=`sysctl hw.ncpu | awk '/hw.ncpu:/ {print $2}'`
182 avail_gb
=$
(check_linux_memory
)
183 avail_cores
=$
((`awk '/cpu cores/ {print $4;exit}' /proc/cpuinfo`*`sort /proc/cpuinfo | uniq | grep -c "physical id"`))
185 echo "Found ${avail_gb}GB of memory and $avail_cores physical CPU cores"
187 # db_shared_buffers: 128MB for 1GB, 256MB for 2GB, or 256MB * GB, max 4096MB
188 if [ "$avail_gb" -eq "1" ]
190 db_shared_buffers
=128
192 if [ "$avail_gb" -eq "2" ]
194 db_shared_buffers
=256
196 db_shared_buffers
=$
(( 256 * $avail_gb ))
199 db_shared_buffers
=$
(( db_shared_buffers
< 4096 ? db_shared_buffers
: 4096 ))
201 sed -i -e "s/^ #\?db_shared_buffers:.*/ db_shared_buffers: \"${db_shared_buffers}MB\"/w $changelog" $config_file
204 echo "setting db_shared_buffers = ${db_shared_buffers}MB"
208 # UNICORN_WORKERS: 2 * GB for 2GB or less, or 2 * CPU, max 8
209 if [ "$avail_gb" -le "2" ]
211 unicorn_workers
=$
(( 2 * $avail_gb ))
213 unicorn_workers
=$
(( 2 * $avail_cores ))
215 unicorn_workers
=$
(( unicorn_workers
< 8 ? unicorn_workers
: 8 ))
217 sed -i -e "s/^ #\?UNICORN_WORKERS:.*/ UNICORN_WORKERS: ${unicorn_workers}/w $changelog" $config_file
220 echo "setting UNICORN_WORKERS = ${unicorn_workers}"
228 ## standard http / https ports must not be occupied
233 echo "Ports 80 and 443 are free for use"
238 ## check a port to see if it is already in use
242 local valid
=$
(netstat
-tln |
awk '{print $4}' |
grep ":${1}\$")
244 if [ -n "$valid" ]; then
245 echo "Port ${1} appears to already be in use."
247 echo "If you are trying to run Discourse simultaneously with another web"
248 echo "server like Apache or nginx, you will need to bind to a different port"
250 echo "See https://meta.discourse.org/t/17247"
252 echo "If you are reconfiguring an already-configured Discourse, use "
254 echo "./launcher stop app"
256 echo "to stop Discourse before you reconfigure it and try again."
262 ## read a variable from the config file
266 config_line
=`egrep "^ #?$1:" $config_file`
267 read_config_result
=`echo $config_line | awk '{print $2}'`
268 read_config_result
=`echo $read_config_result | sed "s/^\([\"']\)\(.*\)\1\$/\2/g"`
274 ## prompt user for typical Discourse config file values
276 ask_user_for_config
() {
278 # NOTE: Defaults now come from standalone.yml
280 local changelog
=/tmp
/changelog.
$PPID
281 read_config
"DISCOURSE_SMTP_ADDRESS"
282 local smtp_address
=$read_config_result
283 # NOTE: if there are spaces between emails, this breaks, but a human should be paying attention
284 read_config
"DISCOURSE_DEVELOPER_EMAILS"
285 local developer_emails
=$read_config_result
286 read_config
"DISCOURSE_SMTP_PASSWORD"
287 local smtp_password
=$read_config_result
288 read_config
"DISCOURSE_SMTP_PORT"
289 local smtp_port
=$read_config_result
290 read_config
"DISCOURSE_SMTP_USER_NAME"
291 local smtp_user_name
=$read_config_result
292 if [ "$smtp_password" = "pa$$word" ]
296 read_config
"LETSENCRYPT_ACCOUNT_EMAIL"
297 local letsencrypt_account_email
=$read_config_result
298 if [ -z $letsencrypt_account_email ]
300 letsencrypt_account_email
="me@example.com"
302 if [ "$letsencrypt_account_email" = "me@example.com" ]
304 local letsencrypt_status
="ENTER to skip"
306 local letsencrypt_status
="Enter 'OFF' to disable."
309 read_config
"DISCOURSE_HOSTNAME"
310 hostname
=$read_config_result
318 while [[ "$config_ok" == "n" ]]
320 if [ ! -z $hostname ]
322 read -p "Hostname for your Discourse? [$hostname]: " new_value
323 if [ ! -z $new_value ]
329 if [ ! -z $developer_emails ]
331 read -p "Email address for admin account(s)? [$developer_emails]: " new_value
332 if [ ! -z $new_value ]
334 developer_emails
=$new_value
338 if [ ! -z $smtp_address ]
340 read -p "SMTP server address? [$smtp_address]: " new_value
341 if [ ! -z $new_value ]
343 smtp_address
=$new_value
347 if [ ! -z $smtp_port ]
349 read -p "SMTP port? [$smtp_port]: " new_value
350 if [ ! -z $new_value ]
357 ## automatically set correct user name based on common mail providers
359 if [ "$smtp_address" == "smtp.sparkpostmail.com" ]
361 smtp_user_name
="SMTP_Injection"
363 if [ "$smtp_address" == "smtp.sendgrid.net" ]
365 smtp_user_name
="apikey"
367 if [ "$smtp_address" == "smtp.mailgun.org" ]
369 smtp_user_name
="postmaster@$hostname"
372 if [ ! -z $smtp_user_name ]
374 read -p "SMTP user name? [$smtp_user_name]: " new_value
375 if [ ! -z $new_value ]
377 smtp_user_name
=$new_value
381 read -p "SMTP password? [$smtp_password]: " new_value
382 if [ ! -z $new_value ]
384 smtp_password
=$new_value
387 if [ ! -z $letsencrypt_account_email ]
389 read -p "Let's Encrypt account email? ($letsencrypt_status) [$letsencrypt_account_email]: " new_value
390 if [ ! -z $new_value ]
392 letsencrypt_account_email
=$new_value
393 if [ "${new_value,,}" = "off" ]
395 letsencrypt_status
="ENTER to skip"
397 letsencrypt_status
="Enter 'OFF' to disable."
402 if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
404 check_IP_match
$hostname
407 echo -e "\nDoes this look right?\n"
408 echo "Hostname : $hostname"
409 echo "Email : $developer_emails"
410 echo "SMTP address : $smtp_address"
411 echo "SMTP port : $smtp_port"
412 echo "SMTP username : $smtp_user_name"
413 echo "SMTP password : $smtp_password"
415 if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
417 echo "Let's Encrypt : $letsencrypt_account_email"
422 read -p "ENTER to continue, 'n' to try again, Ctrl+C to exit: " config_ok
425 sed -i -e "s/^ DISCOURSE_HOSTNAME:.*/ DISCOURSE_HOSTNAME: $hostname/w $changelog" $config_file
430 echo "DISCOURSE_HOSTNAME change failed."
434 sed -i -e "s/^ DISCOURSE_DEVELOPER_EMAILS:.*/ DISCOURSE_DEVELOPER_EMAILS: \'$developer_emails\'/w $changelog" $config_file
439 echo "DISCOURSE_DEVELOPER_EMAILS change failed."
443 sed -i -e "s/^ DISCOURSE_SMTP_ADDRESS:.*/ DISCOURSE_SMTP_ADDRESS: $smtp_address/w $changelog" $config_file
448 echo "DISCOURSE_SMTP_ADDRESS change failed."
452 sed -i -e "s/^ #\?DISCOURSE_SMTP_PORT:.*/ DISCOURSE_SMTP_PORT: $smtp_port/w $changelog" $config_file
457 echo "DISCOURSE_SMTP_PORT change failed."
461 sed -i -e "s/^ #\?DISCOURSE_SMTP_USER_NAME:.*/ DISCOURSE_SMTP_USER_NAME: $smtp_user_name/w $changelog" $config_file
466 echo "DISCOURSE_SMTP_USER_NAME change failed."
470 sed -i -e "s/^ #\?DISCOURSE_SMTP_PASSWORD:.*/ DISCOURSE_SMTP_PASSWORD: \"${smtp_password/\//\\/}\"/w $changelog" $config_file
475 echo "DISCOURSE_SMTP_PASSWORD change failed."
479 if [ "$letsencrypt_status" = "ENTER to skip" ]
481 local src
='^ #\?- "templates\/web.ssl.template.yml"'
482 local dst
=' #\- "templates\/web.ssl.template.yml"'
483 sed -i -e "s/$src/$dst/w $changelog" $config_file
484 if [ ! -s $changelog ]
487 echo "web.ssl.template.yml NOT DISABLED--Are you using a non-standard template?"
489 local src
='^ #\?- "templates\/web.letsencrypt.ssl.template.yml"'
490 local dst
=' #- "templates\/web.letsencrypt.ssl.template.yml"'
492 sed -i -e "s/$src/$dst/w $changelog" $config_file
493 if [ ! -s $changelog ]
496 echo "web.ssl.template.yml NOT DISABLED--Are you using a non-standard template?"
498 else # enable let's encrypt
499 echo "Let's Encrypt will be enabled for $letsencrypt_account_email"
500 sed -i -e "s/^ #\?LETSENCRYPT_ACCOUNT_EMAIL:.*/ LETSENCRYPT_ACCOUNT_EMAIL: $letsencrypt_account_email/w $changelog" $config_file
505 echo "LETSENCRYPT_ACCOUNT_EMAIL change failed."
508 local src
='^ #\?- "templates\/web.ssl.template.yml"'
509 local dst
=' \- "templates\/web.ssl.template.yml"'
510 sed -i -e "s/$src/$dst/w $changelog" $config_file
513 echo "web.ssl.template.yml enabled"
516 echo "web.ssl.template.yml NOT ENABLED--was it on already?"
518 local src
='^ #\?- "templates\/web.letsencrypt.ssl.template.yml"'
519 local dst
=' - "templates\/web.letsencrypt.ssl.template.yml"'
521 sed -i -e "s/$src/$dst/w $changelog" $config_file
524 echo "letsencrypt.ssl.template.yml enabled"
527 echo "letsencrypt.ssl.template.yml NOT ENABLED -- was it on already?"
531 if [ "$update_ok" == "y" ]
533 echo -e "\nConfiguration file at $config_file updated successfully!\n"
535 echo -e "\nUnfortunately, there was an error changing $config_file\n"
541 ## is our config file valid? Does it have the required fields set?
547 for x
in DISCOURSE_SMTP_ADDRESS DISCOURSE_SMTP_USER_NAME DISCOURSE_SMTP_PASSWORD \
548 DISCOURSE_DEVELOPER_EMAILS DISCOURSE_HOSTNAME
550 config_line
=`grep "^ $x:" $config_file`
552 local default
="example.com"
556 if [[ "$config_line" = *"$default"* ]]
558 echo "$x left at incorrect default of example.com"
561 config_val
=`echo $config_line | awk '{print $2}'`
562 if [ -z $config_val ]
564 echo "$x was left blank"
568 echo "$x not present"
573 if [ "$valid_config" != "y" ]; then
574 echo -e "\nSorry, these $config_file settings aren't valid -- can't continue!"
575 echo "If you have unusual requirements, edit $config_file and then: "
576 echo "./launcher bootstrap $app_name"
583 ## template file names
586 template_path
=samples
/standalone.yml
587 config_file
=containers
/$app_name.yml
588 changelog
=/tmp
/changelog
591 ## Check requirements before creating a copy of a config file we won't edit
594 check_and_install_docker
595 check_disk_and_memory
599 ## make a copy of the simple standalone config file
601 if [ -a $config_file ]
603 echo "The configuration file $config_file already exists!"
605 echo ". . . reconfiguring . . ."
607 DATE
=`date +"%Y-%m-%d-%H%M%S"`
608 BACKUP
=$app_name.yml.
$DATE.bak
609 echo Saving old
file as
$BACKUP
610 cp $config_file containers
/$BACKUP
613 cp $template_path $config_file
621 ## if we reach this point without exiting, OK to proceed
622 ## rebuild won't fail if there's nothing to rebuild and does the restart
624 sleep 5 # Just a chance to ^C in case they were too fast on the draw
625 time .
/launcher rebuild
$app_name