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