Merge with auto branch
[discourse_docker.git] / discourse-setup
CommitLineData
f17af951 1#!/usr/bin/env bash
c2d3ee4a 2
ebdd72f3
JA
3##
4## Make sure only root can run our script
5##
6check_root() {
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
9 exit 1
10 fi
11}
12
18602189 13
07f3b11e
JP
14##
15## Does the current IP match the domain name?
16##
17check_IP_match () {
18 echo
19 echo Checking your domain name . . .
20 sleep 1
21 local IFACE=none
22 local IFCONFIG=`which ifconfig`
23 /sbin/route |grep default > /tmp/route$PPID
24
25 if grep default /tmp/route$PPID > /dev/null
26 then
27 local IFACE=`cut -c 73-100 /tmp/route$PPID |head -1`
28 else
29 echo WARNING: Cannot check your IP number.
30 fi
31 local IP=`$IFCONFIG $IFACE|grep "inet addr:" |cut -d":" -f 2|cut -d" " -f1|head -1`
32 local RESOLVED_IP=`dig +short $1`
33
34 IP_LOOKS_GOOD=0
35 if [[ ! -z $RESOLVED_IP ]]
36 then
37 if [ $IP == $RESOLVED_IP ]
38 then
39 echo $1 resolves to $IP. Looks good!
40 echo
41 local IP_LOOKS_GOOD=1
42 fi
43 fi
44 if [ $IP_LOOKS_GOOD == 0 ]
45 then
46 echo "-----------------------------------------"
47 echo $1 does not resolve to $IP.
48 echo IT IS ALMOST CERTAINLY A BAD IDEA TO TURN ON LET\'S ENCRYPT!!
49 echo Unless you know why this check failed, DO NOT USE Let\'s Encrypt.
50 echo
51 echo You should answer \"n\" at the next prompt and disable Let\'s Encrypt.
52 echo You have been warned.
53 echo "-----------------------------------------"
54 fi
55 sleep 1
56}
57
c87c4b0a 58##
18602189
JP
59## Do we have docker?
60##
61check_and_install_docker () {
7cf781fc 62 docker_path=`which docker.io || which docker`
18602189
JP
63 if [ -z $docker_path ]; then
64 read -p "Docker not installed. Enter to install from https://get.docker.com/ or Ctrl+C to exit"
c87c4b0a 65 curl https://get.docker.com/ | sh
18602189 66 fi
7cf781fc 67 docker_path=`which docker.io || which docker`
18602189
JP
68 if [ -z $docker_path ]; then
69 echo Docker install failed. Quitting.
70 exit
71 fi
72}
73
69dcbef5
SG
74##
75## What are we running on
76##
77check_OS() {
78 echo `uname -s`
79}
80
e5ec8aa1
SG
81##
82## OS X available memory
83##
84check_osx_memory() {
85 echo `top -l 1 | awk '/PhysMem:/ {print $2}' | sed s/G//`
86}
87
88##
89## Linux available memory
90##
91check_linux_memory() {
92 echo `free -g --si | awk ' /Mem:/ {print $2} '`
93}
c87c4b0a 94
c2d3ee4a
JA
95##
96## Do we have enough memory and disk space for Discourse?
97##
98check_disk_and_memory() {
c87c4b0a 99
69dcbef5
SG
100 os_type=$(check_OS)
101 avail_mem=0
102 if [ $os_type == "Darwin" ]; then
e5ec8aa1 103 avail_mem=$(check_osx_memory)
69dcbef5 104 else
e5ec8aa1 105 avail_mem=$(check_linux_memory)
69dcbef5
SG
106 fi
107
c6374a12 108 if [ "$avail_mem" -lt 1 ]; then
51890305
JA
109 echo "WARNING: Discourse requires 1GB RAM to run. This system does not appear"
110 echo "to have sufficient memory."
c2d3ee4a 111 echo
51890305
JA
112 echo "Your site may not work properly, or future upgrades of Discourse may not"
113 echo "complete successfully."
c87c4b0a 114 exit 1
cdd99376 115 fi
c87c4b0a 116
f7bb85e6 117 if [ "$avail_mem" -le 2 ]; then
c6374a12
JP
118 total_swap=`free -g --si | awk ' /Swap:/ {print $2} '`
119 if [ "$total_swap" -lt 2 ]; then
bd7e6e26
JP
120 echo "WARNING: Discourse requires at least 2GB of swap when running with 2GB of RAM"
121 echo "or less. This system does not appear to have sufficient swap space."
c2d3ee4a 122 echo
8f70d450 123 echo "Without sufficient swap space, your site may not work properly, and future"
51890305 124 echo "upgrades of Discourse may not complete successfully."
c2d3ee4a 125 echo
ac1a2d67 126 read -p "ENTER to create a 2GB swapfile now, or Ctrl+C to exit"
c87c4b0a 127
8f70d450
JA
128 ##
129 ## derived from https://meta.discourse.org/t/13880
c87c4b0a 130 ##
8f70d450
JA
131 install -o root -g root -m 0600 /dev/null /swapfile
132 dd if=/dev/zero of=/swapfile bs=1k count=2048k
133 mkswap /swapfile
134 swapon /swapfile
7c2777f9 135 echo "/swapfile swap swap auto 0 0" | tee -a /etc/fstab
7802f679 136 sysctl -w vm.swappiness=10
7c2777f9 137 echo vm.swappiness = 10 | tee -a /etc/sysctl.conf
8f70d450 138
c6374a12
JP
139 total_swap=`free -g --si | awk ' /Swap:/ {print $2} '`
140 if [ "$total_swap" -lt 2 ]; then
8f70d450
JA
141 echo "Failed to create swap, sorry!"
142 exit 1
143 fi
c87c4b0a 144
c2d3ee4a
JA
145 fi
146 fi
147
c6374a12 148
c2d3ee4a
JA
149 free_disk="$(df /var | tail -n 1 | awk '{print $4}')"
150 if [ "$free_disk" -lt 5000 ]; then
51890305
JA
151 echo "WARNING: Discourse requires at least 5GB free disk space. This system"
152 echo "does not appear to have sufficient disk space."
c2d3ee4a 153 echo
51890305
JA
154 echo "Insufficient disk space may result in problems running your site, and"
155 echo "may not even allow Discourse installation to complete successfully."
c2d3ee4a
JA
156 echo
157 echo "Please free up some space, or expand your disk, before continuing."
158 echo
51890305
JA
159 echo "Run \`apt-get autoremove && apt-get autoclean\` to clean up unused"
160 echo "packages and \`./launcher cleanup\` to remove stale Docker containers."
c2d3ee4a
JA
161 exit 1
162 fi
163
c2d3ee4a
JA
164}
165
166
167##
168## If we have lots of RAM or lots of CPUs, bump up the defaults to scale better
169##
170scale_ram_and_cpu() {
171
642b870f 172 local changelog=/tmp/changelog.$PPID
c2d3ee4a 173 # grab info about total system ram and physical (NOT LOGICAL!) CPU cores
e5ec8aa1
SG
174 avail_gb=0
175 avail_cores=0
176 os_type=$(check_OS)
177 if [ $os_type == "Darwin" ]; then
178 avail_gb=$(check_osx_memory)
179 avail_cores=`sysctl hw.ncpu | awk '/hw.ncpu:/ {print $2}'`
180 else
96568673
TH
181 avail_gb=$(check_linux_memory)
182 avail_cores=$((`awk '/cpu cores/ {print $4;exit}' /proc/cpuinfo`*`sort /proc/cpuinfo | uniq | grep -c "physical id"`))
e5ec8aa1 183 fi
c2d3ee4a
JA
184 echo "Found ${avail_gb}GB of memory and $avail_cores physical CPU cores"
185
186 # db_shared_buffers: 128MB for 1GB, 256MB for 2GB, or 256MB * GB, max 4096MB
187 if [ "$avail_gb" -eq "1" ]
188 then
189 db_shared_buffers=128
190 else
191 if [ "$avail_gb" -eq "2" ]
192 then
193 db_shared_buffers=256
194 else
195 db_shared_buffers=$(( 256 * $avail_gb ))
196 fi
197 fi
198 db_shared_buffers=$(( db_shared_buffers < 4096 ? db_shared_buffers : 4096 ))
199
f17af951 200 sed -i -e "s/^ #\?db_shared_buffers:.*/ db_shared_buffers: \"${db_shared_buffers}MB\"/w $changelog" $config_file
c2d3ee4a
JA
201 if [ -s $changelog ]
202 then
203 echo "setting db_shared_buffers = ${db_shared_buffers}MB"
204 rm $changelog
205 fi
206
c2d3ee4a
JA
207 # UNICORN_WORKERS: 2 * GB for 2GB or less, or 2 * CPU, max 8
208 if [ "$avail_gb" -le "2" ]
209 then
210 unicorn_workers=$(( 2 * $avail_gb ))
211 else
212 unicorn_workers=$(( 2 * $avail_cores ))
213 fi
214 unicorn_workers=$(( unicorn_workers < 8 ? unicorn_workers : 8 ))
215
f17af951 216 sed -i -e "s/^ #\?UNICORN_WORKERS:.*/ UNICORN_WORKERS: ${unicorn_workers}/w $changelog" $config_file
c2d3ee4a
JA
217 if [ -s $changelog ]
218 then
219 echo "setting UNICORN_WORKERS = ${unicorn_workers}"
220 rm $changelog
221 fi
222
223}
224
225
c87c4b0a 226##
c2d3ee4a
JA
227## standard http / https ports must not be occupied
228##
229check_ports() {
230 check_port "80"
231 check_port "443"
232 echo "Ports 80 and 443 are free for use"
233}
234
235
236##
237## check a port to see if it is already in use
238##
239check_port() {
c87c4b0a 240
c2d3ee4a
JA
241 local valid=$(netstat -tln | awk '{print $4}' | grep ":${1}\$")
242
243 if [ -n "$valid" ]; then
244 echo "Port ${1} appears to already be in use."
245 echo
51890305
JA
246 echo "If you are trying to run Discourse simultaneously with another web"
247 echo "server like Apache or nginx, you will need to bind to a different port"
c87c4b0a 248 echo
51890305 249 echo "See https://meta.discourse.org/t/17247"
f17af951
JP
250 echo
251 echo "If you are reconfiguring an already-configured Discourse, use "
252 echo
253 echo "./launcher stop app"
254 echo
255 echo "to stop Discourse before you reconfigure it and try again."
c2d3ee4a
JA
256 exit 1
257 fi
258}
259
f17af951
JP
260##
261## read a variable from the config file
262##
263read_config() {
264
265 config_line=`egrep "^ #?$1:" $config_file`
266 read_config_result=`echo $config_line | awk '{print $2}'`
267 read_config_result=`echo $read_config_result | sed "s/^\([\"']\)\(.*\)\1\$/\2/g"`
268}
269
270
271
c2d3ee4a
JA
272##
273## prompt user for typical Discourse config file values
274##
4b1b25e3 275ask_user_for_config() {
c87c4b0a 276
f17af951
JP
277 # NOTE: Defaults now come from standalone.yml
278
642b870f 279 local changelog=/tmp/changelog.$PPID
f17af951
JP
280 read_config "DISCOURSE_SMTP_ADDRESS"
281 local smtp_address=$read_config_result
282 # NOTE: if there are spaces between emails, this breaks, but a human should be paying attention
283 read_config "DISCOURSE_DEVELOPER_EMAILS"
284 local developer_emails=$read_config_result
285 read_config "DISCOURSE_SMTP_PASSWORD"
286 local smtp_password=$read_config_result
287 read_config "DISCOURSE_SMTP_PORT"
288 local smtp_port=$read_config_result
289 read_config "DISCOURSE_SMTP_USER_NAME"
290 local smtp_user_name=$read_config_result
291 if [ "$smtp_password" = "pa$$word" ]
292 then
293 smtp_password = ""
294 fi
295 read_config "LETSENCRYPT_ACCOUNT_EMAIL"
296 local letsencrypt_account_email=$read_config_result
297 if [ $letsencrypt_account_email = "me@example.com" ]
298 then
299 local letsencrypt_status="ENTER to skip"
300 else
301 local letsencrypt_status="Enter 'OFF' to disable."
302 fi
303
304 read_config "DISCOURSE_HOSTNAME"
305 hostname=$read_config_result
c2d3ee4a
JA
306
307 local new_value=""
308 local config_ok="n"
309 local update_ok="y"
c87c4b0a 310
c2d3ee4a
JA
311 echo ""
312
313 while [[ "$config_ok" == "n" ]]
314 do
315 if [ ! -z $hostname ]
316 then
317 read -p "Hostname for your Discourse? [$hostname]: " new_value
318 if [ ! -z $new_value ]
319 then
320 hostname=$new_value
321 fi
322 fi
c87c4b0a 323
c2d3ee4a
JA
324 if [ ! -z $developer_emails ]
325 then
f17af951 326 read -p "Email address for admin account(s)? [$developer_emails]: " new_value
c2d3ee4a
JA
327 if [ ! -z $new_value ]
328 then
329 developer_emails=$new_value
330 fi
331 fi
c87c4b0a 332
c2d3ee4a
JA
333 if [ ! -z $smtp_address ]
334 then
335 read -p "SMTP server address? [$smtp_address]: " new_value
336 if [ ! -z $new_value ]
337 then
338 smtp_address=$new_value
339 fi
340 fi
c87c4b0a 341
7c2777f9 342 if [ ! -z $smtp_port ]
c2d3ee4a 343 then
7c2777f9
JA
344 read -p "SMTP port? [$smtp_port]: " new_value
345 if [ ! -z $new_value ]
346 then
347 smtp_port=$new_value
348 fi
c2d3ee4a 349 fi
c87c4b0a 350
7c2777f9
JA
351 ##
352 ## automatically set correct user name based on common mail providers
353 ##
354 if [ "$smtp_address" == "smtp.sparkpostmail.com" ]
355 then
356 smtp_user_name="SMTP_Injection"
c87c4b0a 357 fi
c2d3ee4a
JA
358 if [ "$smtp_address" == "smtp.sendgrid.net" ]
359 then
360 smtp_user_name="apikey"
361 fi
7c2777f9
JA
362 if [ "$smtp_address" == "smtp.mailgun.org" ]
363 then
364 smtp_user_name="postmaster@$hostname"
365 fi
c87c4b0a 366
c2d3ee4a
JA
367 if [ ! -z $smtp_user_name ]
368 then
369 read -p "SMTP user name? [$smtp_user_name]: " new_value
370 if [ ! -z $new_value ]
371 then
372 smtp_user_name=$new_value
373 fi
374 fi
c87c4b0a 375
c2d3ee4a
JA
376 read -p "SMTP password? [$smtp_password]: " new_value
377 if [ ! -z $new_value ]
378 then
379 smtp_password=$new_value
380 fi
c87c4b0a 381
c2d3ee4a
JA
382 if [ ! -z $letsencrypt_account_email ]
383 then
384 read -p "Let's Encrypt account email? ($letsencrypt_status) [$letsencrypt_account_email]: " new_value
385 if [ ! -z $new_value ]
386 then
387 letsencrypt_account_email=$new_value
f17af951 388 if [ "${new_value,,}" = "off" ]
c2d3ee4a
JA
389 then
390 letsencrypt_status="ENTER to skip"
391 else
392 letsencrypt_status="Enter 'OFF' to disable."
393 fi
394 fi
395 fi
396
07f3b11e
JP
397 if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
398 then
399 check_IP_match $hostname
400 fi
401
51890305 402 echo -e "\nDoes this look right?\n"
c2d3ee4a
JA
403 echo "Hostname : $hostname"
404 echo "Email : $developer_emails"
405 echo "SMTP address : $smtp_address"
7c2777f9 406 echo "SMTP port : $smtp_port"
c2d3ee4a
JA
407 echo "SMTP username : $smtp_user_name"
408 echo "SMTP password : $smtp_password"
c87c4b0a 409
c2d3ee4a
JA
410 if [ "$letsencrypt_status" == "Enter 'OFF' to disable." ]
411 then
412 echo "Let's Encrypt : $letsencrypt_account_email"
413 fi
c87c4b0a 414
07f3b11e 415
c2d3ee4a 416 echo ""
ac1a2d67 417 read -p "ENTER to continue, 'n' to try again, Ctrl+C to exit: " config_ok
c2d3ee4a
JA
418 done
419
013b5931 420 sed -i -e "s/^ DISCOURSE_HOSTNAME:.*/ DISCOURSE_HOSTNAME: $hostname/w $changelog" $config_file
c2d3ee4a
JA
421 if [ -s $changelog ]
422 then
423 rm $changelog
424 else
425 echo "DISCOURSE_HOSTNAME change failed."
426 update_ok="n"
427 fi
428
429 sed -i -e "s/^ DISCOURSE_DEVELOPER_EMAILS:.*/ DISCOURSE_DEVELOPER_EMAILS: \'$developer_emails\'/w $changelog" $config_file
430 if [ -s $changelog ]
431 then
432 rm $changelog
433 else
434 echo "DISCOURSE_DEVELOPER_EMAILS change failed."
435 update_ok="n"
436 fi
437
013b5931 438 sed -i -e "s/^ DISCOURSE_SMTP_ADDRESS:.*/ DISCOURSE_SMTP_ADDRESS: $smtp_address/w $changelog" $config_file
c2d3ee4a
JA
439 if [ -s $changelog ]
440 then
441 rm $changelog
442 else
443 echo "DISCOURSE_SMTP_ADDRESS change failed."
444 update_ok="n"
445 fi
446
f17af951 447 sed -i -e "s/^ #\?DISCOURSE_SMTP_PORT:.*/ DISCOURSE_SMTP_PORT: $smtp_port/w $changelog" $config_file
7c2777f9
JA
448 if [ -s $changelog ]
449 then
450 rm $changelog
451 else
452 echo "DISCOURSE_SMTP_PORT change failed."
453 update_ok="n"
454 fi
455
f17af951 456 sed -i -e "s/^ #\?DISCOURSE_SMTP_USER_NAME:.*/ DISCOURSE_SMTP_USER_NAME: $smtp_user_name/w $changelog" $config_file
c2d3ee4a
JA
457 if [ -s $changelog ]
458 then
459 rm $changelog
460 else
461 echo "DISCOURSE_SMTP_USER_NAME change failed."
462 update_ok="n"
463 fi
464
f17af951 465 sed -i -e "s/^ #\?DISCOURSE_SMTP_PASSWORD:.*/ DISCOURSE_SMTP_PASSWORD: \"${smtp_password/\//\\/}\"/w $changelog" $config_file
c2d3ee4a
JA
466 if [ -s $changelog ]
467 then
468 rm $changelog
469 else
470 echo "DISCOURSE_SMTP_PASSWORD change failed."
471 update_ok="n"
472 fi
473
f17af951 474 if [ "$letsencrypt_status" = "ENTER to skip" ]
c2d3ee4a 475 then
f17af951
JP
476 local src='^ #\?- "templates\/web.ssl.template.yml"'
477 local dst=' #\- "templates\/web.ssl.template.yml"'
478 sed -i -e "s/$src/$dst/w $changelog" $config_file
2391b7fc 479 if [ ! -s $changelog ]
f17af951 480 then
f17af951
JP
481 update_ok="n"
482 echo "web.ssl.template.yml NOT DISABLED--Are you using a non-standard template?"
483 fi
484 local src='^ #\?- "templates\/web.letsencrypt.ssl.template.yml"'
485 local dst=' #- "templates\/web.letsencrypt.ssl.template.yml"'
486
487 sed -i -e "s/$src/$dst/w $changelog" $config_file
2391b7fc 488 if [ ! -s $changelog ]
f17af951 489 then
f17af951
JP
490 update_ok="n"
491 echo "web.ssl.template.yml NOT DISABLED--Are you using a non-standard template?"
492 fi
493 else # enable let's encrypt
494 echo "Let's Encrypt will be enabled for $letsencrypt_account_email"
495 sed -i -e "s/^ #\?LETSENCRYPT_ACCOUNT_EMAIL:.*/ LETSENCRYPT_ACCOUNT_EMAIL: $letsencrypt_account_email/w $changelog" $config_file
c2d3ee4a
JA
496 if [ -s $changelog ]
497 then
498 rm $changelog
499 else
500 echo "LETSENCRYPT_ACCOUNT_EMAIL change failed."
501 update_ok="n"
502 fi
f17af951 503 local src='^ #\?- "templates\/web.ssl.template.yml"'
c2d3ee4a
JA
504 local dst=' \- "templates\/web.ssl.template.yml"'
505 sed -i -e "s/$src/$dst/w $changelog" $config_file
506 if [ -s $changelog ]
507 then
642b870f 508 echo "web.ssl.template.yml enabled"
c2d3ee4a
JA
509 else
510 update_ok="n"
511 echo "web.ssl.template.yml NOT ENABLED--was it on already?"
512 fi
f17af951 513 local src='^ #\?- "templates\/web.letsencrypt.ssl.template.yml"'
c2d3ee4a
JA
514 local dst=' - "templates\/web.letsencrypt.ssl.template.yml"'
515
516 sed -i -e "s/$src/$dst/w $changelog" $config_file
517 if [ -s $changelog ]
518 then
519 echo "letsencrypt.ssl.template.yml enabled"
520 else
521 update_ok="n"
522 echo "letsencrypt.ssl.template.yml NOT ENABLED -- was it on already?"
523 fi
c87c4b0a 524 fi
c2d3ee4a
JA
525
526 if [ "$update_ok" == "y" ]
527 then
528 echo -e "\nConfiguration file at $config_file updated successfully!\n"
529 else
530 echo -e "\nUnfortunately, there was an error changing $config_file\n"
531 exit 1
532 fi
533}
534
535##
536## is our config file valid? Does it have the required fields set?
537##
4b1b25e3 538validate_config() {
c2d3ee4a
JA
539
540 valid_config="y"
c87c4b0a 541
c2d3ee4a
JA
542 for x in DISCOURSE_SMTP_ADDRESS DISCOURSE_SMTP_USER_NAME DISCOURSE_SMTP_PASSWORD \
543 DISCOURSE_DEVELOPER_EMAILS DISCOURSE_HOSTNAME
544 do
c87c4b0a 545 config_line=`grep "^ $x:" $config_file`
c2d3ee4a
JA
546 local result=$?
547 local default="example.com"
548
549 if (( result == 0 ))
550 then
551 if [[ $config_line = *"$default"* ]]
552 then
553 echo "$x left at incorrect default of example.com"
554 valid_config="n"
555 fi
556 config_val=`echo $config_line | awk '{print $2}'`
557 if [ -z $config_val ]
558 then
559 echo "$x was left blank"
560 valid_config="n"
561 fi
562 else
563 echo "$x not present"
564 valid_config="n"
565 fi
566 done
c87c4b0a 567
c2d3ee4a
JA
568 if [ "$valid_config" != "y" ]; then
569 echo -e "\nSorry, these $config_file settings aren't valid -- can't continue!"
d8613c71
JA
570 echo "If you have unusual requirements, edit $config_file and then: "
571 echo "./launcher bootstrap $app_name"
c2d3ee4a
JA
572 exit 1
573 fi
574}
575
576
577##
578## template file names
579##
580app_name=app
581template_path=samples/standalone.yml
582config_file=containers/$app_name.yml
583changelog=/tmp/changelog
584
4b1b25e3
JA
585##
586## Check requirements before creating a copy of a config file we won't edit
587##
ebdd72f3 588check_root
18602189 589check_and_install_docker
642b870f
JP
590check_disk_and_memory
591check_ports
592
4b1b25e3 593##
c2d3ee4a 594## make a copy of the simple standalone config file
4b1b25e3 595##
c2d3ee4a
JA
596if [ -a $config_file ]
597then
598 echo "The configuration file $config_file already exists!"
f17af951
JP
599 echo
600 echo ". . . reconfiguring . . ."
601 echo
c2d3ee4a
JA
602else
603 cp $template_path $config_file
604fi
605
c2d3ee4a 606scale_ram_and_cpu
4b1b25e3
JA
607ask_user_for_config
608validate_config
c2d3ee4a 609
4b1b25e3
JA
610##
611## if we reach this point without exiting, OK to proceed
f17af951 612## rebuild won't fail if there's nothing to rebuild and does the restart
4b1b25e3 613##
f17af951
JP
614sleep 5 # Just a chance to ^C in case they were too fast on the draw
615time ./launcher rebuild $app_name