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