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