2 LOG_FILE
="/tmp/discourse-debug.txt"
3 WORKING_DIR
="$( cd "$
( dirname "${BASH_SOURCE[0]}" )" && pwd )"
9 echo -e "$*" |
tee -a "$LOG_FILE"
11 echo "$*" |
tee -a "$LOG_FILE"
16 if [[ $EUID -ne 0 ]]; then
17 log
"This script must be run as root. Please sudo or log in as root first." 1>&2
23 ## Check whether a connection to HOSTNAME ($1) on PORT ($2) is possible
28 VERIFY
=$
(date +%s | sha256sum | base64 |
head -c 20)
29 echo -e "HTTP/1.1 200 OK\n\n $VERIFY" | nc
-w 4 -l -p $PORT >/dev
/null
2>&1 &
30 if curl
--proto =http
-s $HOST:$PORT --connect-timeout 3 |
grep $VERIFY >/dev
/null
2>&1 &
41 log Checking your domain name . . .
42 if connect_to_port
$HOST 443
45 log
"Connection to $HOST succeeded."
47 log WARNING
:: This server does not appear to be accessible
at $HOST:443.
49 if connect_to_port
$HOST 80
51 log A connection to port
80 succeeds
, however.
52 log This suggests that your DNS settings are correct
,
53 log but something is keeping traffic to port
443 from getting to your server.
54 log Check your networking configuration to see that connections to port
443 are allowed.
56 log
"A connection to http://$HOST (port 80) also fails."
58 log This suggests that
$HOST resolves to the wrong IP address
59 log or that traffic is not being routed to your server.
62 log Google
: \"open ports YOUR CLOUD SERVICE
\" for information
for resolving this problem.
64 log This
test might not work
for all situations
,
65 log so
if you can access Discourse
at http
://$HOST, this might not indicate a problem.
70 check_docker_is_installed
() {
71 log
-e "\n==================== DOCKER INFO ===================="
72 docker_path
="$(which docker.io || which docker)"
73 if [ -z $docker_path ]; then
74 log
"Docker is not installed. Have you installed Discourse at all?"
75 log
"Perhaps you're looking for ./discourse-setup ."
76 log
"There is no point in continuing."
79 log
-e "DOCKER VERSION: $(docker --version)"
80 log
-e "\nDOCKER PROCESSES (docker ps -a)\n\n$(sudo docker ps -a)\n"
85 log
-e "OS: $(uname -s)"
88 check_disk_and_memory
() {
89 log
-e "\n\n==================== MEMORY INFORMATION ===================="
91 if [ "$os_type" == "Darwin" ]; then
92 log
-e "RAM: $( free -m | awk '/Mem:/ {print $2}' ) \n"
94 log
-e "RAM (MB): $( free -m --si | awk ' /Mem:/ {print $2} ')\n"
98 log
-e "\n==================== DISK SPACE CHECK ===================="
99 log
"---------- OS Disk Space ----------"
100 log
"$(df -h / /var/discourse /var/lib/docker /var/lib/docker/* | uniq)"
102 if [ "$version" != "NOT FOUND" ]
105 log
"---------- Container Disk Space ----------"
106 log
"$(sudo docker exec -w /var/www/discourse -i $app_name df -h / /shared/ /shared/postgres_data /shared/redis_data /shared/backups /var/log | uniq)"
109 log
-e "\n==================== DISK INFORMATION ===================="
111 log
-e "\n==================== END DISK INFORMATION ===================="
113 free_disk
="$(df /var | tail -n 1 | awk '{print $4}')"
114 # Arguably ./launcher is doing this so discourse-doctor does not need to . . .
115 if [ "$free_disk" -lt 5000 ]; then
116 log
"\n\n==================== DISK SPACE PROBLEM ===================="
117 log
"WARNING: you appear to have very low disk space."
118 log
"This could be the cause of problems running your site."
119 log
"Please free up some space, or expand your disk, before continuing."
121 log
"Run \'apt-get autoremove && apt-get autoclean\' to clean up unused"
122 log
"packages and \'./launcher cleanup\' to remove stale Docker containers."
127 get_discourse_version
() {
129 version
=$
(wget
-q --timeout=3 https
://$VERSION_HOSTNAME/privacy
-O -|
grep generator|
head -1 |cut
-d "=" -f 3|cut
-d '-' -f 1 |cut
-d '"' -f 2) &> /dev
/null
130 if ! echo $version |
grep Discourse
132 version
=$
(wget
-q --timeout=3 http
://$VERSION_HOSTNAME/privacy
-O -|
grep generator|
head -1 |cut
-d "=" -f 3|cut
-d '-' -f 1 |cut
-d '"' -f 2) &> /dev
/null
138 log
"Discourse version at $VERSION_HOSTNAME: $version"
141 check_if_hostname_resolves_here
() {
142 log
"========================================"
143 VERSION_HOSTNAME
=$DISCOURSE_HOSTNAME
144 get_discourse_version
145 DISCOURSE_VERSION
="$version"
146 VERSION_HOSTNAME
=localhost
147 get_discourse_version
148 LOCALHOST_VERSION
="$version"
149 if [ "$DISCOURSE_VERSION" != "$LOCALHOST_VERSION" ]
151 log
"==================== DNS PROBLEM ===================="
152 log
"This server reports $LOCALHOST_VERSION, but $DISCOURSE_HOSTNAME reports $DISCOURSE_VERSION."
153 log
"This suggests that you have a DNS problem or that an intermediate proxy is to blame."
154 log
"If you are using Cloudflare, or a CDN, it may be improperly configured."
159 ## get discourse configuration values from YML file
161 get_discourse_config
() {
162 log
-e "\n==================== YML SETTINGS ===================="
163 read_config
"DISCOURSE_HOSTNAME"
164 DISCOURSE_HOSTNAME
=$read_config_result
165 log DISCOURSE_HOSTNAME
=$DISCOURSE_HOSTNAME
166 read_config
"DISCOURSE_SMTP_ADDRESS"
167 SMTP_ADDRESS
=$read_config_result
168 log SMTP_ADDRESS
=$SMTP_ADDRESS
169 read_config
"DISCOURSE_DEVELOPER_EMAILS"
170 DEVELOPER_EMAILS
=$read_config_result
171 log DEVELOPER_EMAILS
=$DEVELOPER_EMAILS
172 read_config
"DISCOURSE_SMTP_PASSWORD"
173 SMTP_PASSWORD
=$read_config_result
174 log SMTP_PASSWORD
=$read_config_result
175 read_config
"DISCOURSE_SMTP_PORT"
176 SMTP_PORT
=$read_config_result
177 log SMTP_PORT
=$read_config_result
178 read_config
"DISCOURSE_SMTP_USER_NAME"
179 SMTP_USER_NAME
=$read_config_result
180 log SMTP_USER_NAME
=$read_config_result
181 read_config
"LETSENCRYPT_ACCOUNT_EMAIL"
182 letsencrypt_account_email
=$read_config_result
183 log
"LETSENCRYPT_ACCOUNT_EMAIL=$letsencrypt_account_email"
187 log
-e "\n\n==================== PLUGINS ===================="
188 log
-e "$(grep git containers/$app_name.yml)"
189 grep git containers
/$app_name.yml
> /tmp
/$PPID.
grep
191 if grep -cv "github.com/discourse" /tmp
/$PPID.
grep > /dev
/null
194 log You have what appear to be non-official plugins.
195 log
"If you are having trouble, you should disable them and try rebuilding again."
197 log
-e "\nNo non-official plugins detected."
199 log
-e "\nSee https://github.com/discourse/discourse/blob/master/lib/plugin/metadata.rb for the official list.\n"
203 log
-e "\n\n==================== YML DUMP ===================="
204 log Dumping
$app_name.yml
209 ## read a variable from the config file and stick it in read_config_result
212 config_line
=$
(egrep "^ #?$1:" $web_file)
213 read_config_result
=$
(echo $config_line |
awk --field-separator=":" '{print $2}')
214 read_config_result
=$
(echo $read_config_result |
sed "s/^\([\"']\)\(.*\)\1\$/\2/g")
218 ## call rake emails:test inside the container
221 log
-e "\n==================== MAIL TEST ===================="
222 log
"For a robust test, get an address from http://www.mail-tester.com/"
223 echo "Or just send a test message to yourself."
224 EMAIL
=$
(echo $DEVELOPER_EMAILS |cut
-d , -f 1)
225 read -p "Email address for mail test? ('n' to skip) [$EMAIL]: " new_value
226 if [ ! -z "$new_value" ]
230 if [ "$new_value" != "n" ] && [ "$new_value" != "N" ]
232 log
"Sending mail to $EMAIL. . . "
233 log
"$(sudo docker exec -w /var/www/discourse -i $app_name rake emails:test[$EMAIL])"
235 log
"Mail test skipped."
241 if [ -f containers
/app.yml
]
244 web_file
=containers
/$app_name.yml
245 log
"Found $web_file"
246 elif [ -f containers
/web_only.yml
]
248 log
"YML=web_only.yml"
250 web_file
=containers
/$app_name.yml
251 log
"Found $web_file"
253 log
"Can't find app.yml or web_only.yml."
260 docker ps |
tail -n +2 > /tmp
/$UUID-docker.txt
262 if grep $app_name /tmp
/$UUID-docker.txt
264 log
-e "\nDiscourse container $app_name is running"
266 log
"==================== SERIOUS PROBLEM!!!! ===================="
267 log
"$app_name not running!"
268 log
"Attempting to rebuild"
269 log
"==================== REBUILD LOG ===================="
270 # too hard to pass STDERR of ./launcher to log()
271 .
/launcher rebuild
$app_name 2>&1 |
tee -a $LOG_FILE
272 log
"==================== END REBUILD LOG ===================="
273 docker ps|
tail -n +2 > /tmp
/$UUID-docker.txt
274 if grep $app_name /tmp
/$UUID-docker.txt
276 log
-e "\nDiscourse container $app_name is now running."
277 log
". . . waiting 30 seconds for container to crank up. . . "
280 log
"$app_name still not running!"
281 # check_ip_match checks if curl to $DISCOURSE_HOSTNAME gets to this server
282 # It works only if ports 80 and 443 are free
283 check_ip_match
$DISCOURSE_HOSTNAME
284 log
"You should probably remove any non-standard plugins and rebuild."
291 ## redact passwords and email addresses from log file
293 clean_up_log_file
() {
295 in SMTP_PASSWORD LETSENCRYPT_ACCOUNT_EMAIL DEVELOPER_EMAILS DISCOURSE_DB_PASSWORD
'Sending mail to'
297 echo "Replacing: $VAR"
298 sed -i -e 's/'"$VAR"'\([=: ]\)\S*/'"$VAR"'\1REDACTED /g' $LOG_FILE
304 log
"==================== DONE! ===================="
305 DOCTOR_FILE
=$
(date +%s | sha256sum | base64 |
head -c 20).txt
307 if [ $app_name == 'app' ] && [ "$NO_CONTAINER" != 'y' ]
309 cp $LOG_FILE shared
/standalone
/log
/var-log
/$DOCTOR_FILE
310 sudo docker
exec -w /var
/www
/discourse
-i $app_name cp /var
/log
/$DOCTOR_FILE public
311 log
"The output of this program may be available at http://$DISCOURSE_HOSTNAME/$DOCTOR_FILE"
312 log
"You should inspect that file carefully before sharing the URL."
314 # The following is not in the web log file since it was copied above, which seems corect
316 log
"You can examine the output of this script with "
317 log
"LESS=-Ri less $LOG_FILE"
319 log
"BUT FIRST, make sure that you know the first three commands below!!!"
321 log
"Commands to know when viewing the file with the above command (called 'less'): "
323 log
"/error<ENTER> -- search for the word 'error'"
324 log
"n -- search for the next occurrence"
325 log
"g -- go to the beginning of the file"
326 log
"f -- go forward a page"
327 log
"b -- go back a page"
328 log
"G -- go to the end of the file"
331 initialize_log_file
() {
334 log DISCOURSE DOCTOR $
(date)
335 log
-e "OS: $(uname -a)\n\n"
339 ## END FUNCTION DECLARATION
343 cd $WORKING_DIR ||
exit
347 check_docker_is_installed
350 check_if_hostname_resolves_here
351 check_disk_and_memory