Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A helper script to automatically setup a DOMjudge server in 10 minutes, go get yourself a coffee.
#!/usr/bin/env bash
#
# This is a script that can automatically
# setup DOMjudge server & judgehost, inside a same server.
#
# As a bonus, this script will also setup a beautiful DOMjudge
# interface made using React, which it will listen on port 8080.
#
# This script assumes that:
# 1) You're using Ubuntu 17.10. (6-April-2018 tested and working)
# 2) You have a clean Ubuntu 17.10. (freshly installed)
# 3) You will run this script as root.
#
# SERVER_DOMAIN and OWNER_EMAIL is optional. If both are empty then
# this script will create its own SSL self-signed certificate (with broken lock
# if you see it with your browser). If you specify them both, this script
# will use Lets Encrypt certificate, which IMO is much better. (no broken lock ;)
#
# you can leave it by its default value
USERNAME=domjudge
USER_PASSWORD=domjudge
MYSQL_PWD=root
PHPMYADMIN_PWD=root
REACT_DOMJUDGE_PORT=8080
# leave both of these empty if you don't have any domain
SERVER_DOMAIN=''
OWNER_EMAIL=''
# do case insensitive comparison
shopt -s nocasematch
if [[ ! $EUID -ne 0 ]]; then
start_time=$(date +%s)
if [ -d "/home/$USERNAME" ]; then
echo ""
echo "#############################################################"
echo " DOMJudge has already been configured inside this server!! "
echo "#############################################################"
echo ""
echo "Do you want to delete $USERNAME user and retry this again?"
echo "Please do note that this method usually won't work..."
echo "Best bet is to reset your server again with newly freshed Ubuntu 17.10"
read -p "Continue? [Y/n] : " overwrite_current
if [[ ${overwrite_current:0:1} == 'y' || -z "$overwrite_current" ]]; then
deluser --remove-home $USERNAME
else
exit 1
fi
fi
getent passwd $USERNAME > /dev/null 2&>1
RES=$?
if [ ! $RES -eq 0 ]; then
echo ""
echo "############################################"
echo " '$USERNAME' not exist. Creating... "
echo "############################################"
echo ""
useradd -d /home/$USERNAME -s /bin/bash -m $USERNAME && echo $USER_PASSWORD:$USER_PASSWORD | chpasswd
# give sudoer permission to our new user
echo "$USERNAME ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
fi
# re-run this script with $USERNAME access
cp $0 /home/$USERNAME/
chown $USERNAME:$USERNAME /home/$USERNAME/$0
chmod 777 /home/$USERNAME/$0
su -s /bin/bash -c "/home/$USERNAME/$0" $USERNAME
IP_ADDR=$(sudo wget -qO- ipinfo.io/ip)
[[ -z "$SERVER_DOMAIN" ]] && HOST_NAME="$IP_ADDR" || HOST_NAME="$SERVER_DOMAIN"
echo ""
echo ""
echo ""
echo "=================================================================================="
echo ""
echo ""
echo ""
echo "All finished!"
echo ""
echo "Time taken: $(date -d @$(($(date +%s)-$start_time)) +"%M minutes %S seconds")"
echo ""
echo "Next time you can SSH into your server by using '$USERNAME' user."
echo " Username: $USERNAME"
echo " Password: $USER_PASSWORD"
echo ""
echo "To configure your DOMjudge system, you can visit https://$HOST_NAME/ and login using"
echo "'admin' for both username and password. For team submission, there are two ways, either"
echo "using pure DOMjudge interface (which is ugly) at https://$HOST_NAME/, or you can ask them"
echo "to visit http://$HOST_NAME:8080/, which is a nice submission interface made using React."
echo ""
echo ""
echo ""
echo "This server need to be restarted in order for chroot option to be mounted by grub in boot-time."
echo ""
read -p "Do you want to reboot now? [Y/n]: " reboot_now
if [[ ${reboot_now:0:1} == 'y' || -z "$reboot_now" ]]; then
reboot
fi
exit 1
fi
echo ""
echo -e "################################"
echo -e " Running as user: $USER "
echo -e "################################"
echo ""
PATH=$PATH:/sbin:/usr/sbin
IP_ADDR=$(sudo wget -qO- ipinfo.io/ip)
echo ""
echo '####################'
echo ' Upgrading System '
echo '####################'
echo ""
sudo apt -y update
# sudo apt -y upgrade
echo ""
echo '##########################'
echo ' Installing dependencies '
echo '##########################'
echo ""
# use newer version of nodejs
curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash -
sudo apt -y install nodejs
sudo apt -y install gcc g++ make zip unzip \
apache2 php php-cli libapache2-mod-php \
php-gd php-curl php-mysql php-json php-zip \
php-mcrypt php-gmp php-xml php-mbstring \
bsdmainutils ntp libcgroup-dev \
linuxdoc-tools linuxdoc-tools-text \
groff texlive-latex-recommended texlive-latex-extra \
texlive-fonts-recommended texlive-lang-european curl git
sudo apt -y install libcurl4-gnutls-dev libjsoncpp-dev libmagic-dev
echo ""
echo '###################################'
echo ' Installing appropriate compilers '
echo '###################################'
echo ""
sudo apt -y install make sudo debootstrap libcgroup-dev \
php-cli php-curl php-json php-zip procps \
gcc g++ openjdk-8-jre-headless \
openjdk-8-jdk ghc fp-compiler
echo ""
echo '#####################'
echo ' Installing MySQL '
echo '#####################'
echo ""
echo "mysql-server mysql-server/root_password password $MYSQL_PWD" | sudo debconf-set-selections
echo "mysql-server mysql-server/root_password_again password $MYSQL_PWD" | sudo debconf-set-selections
sudo apt -y install mysql-server expect
# automate mysql_secure_installation
SECURE_MYSQL=$(expect -c "
set timeout 3
spawn mysql_secure_installation
expect \"Enter password for user root:\"
send \"$MYSQL_PWD\r\"
expect \"Press y|Y for Yes, any other key for No\"
send \"n\r\"
expect \"Change the password for root?\"
send \"n\r\"
expect \"Remove anonymous users?\"
send \"y\r\"
expect \"Disallow root login remotely?\"
send \"y\r\"
expect \"Remove test database and access to it?\"
send \"y\r\"
expect \"Reload privilege tables now?\"
send \"y\r\"
expect eof
")
echo "$SECURE_MYSQL"
sudo systemctl start mysql
mysql -u root -p$MYSQL_PWD -D mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root';flush privileges;"
echo ""
echo '#########################'
echo ' Installing phpmyadmin '
echo '#########################'
echo ""
echo phpmyadmin phpmyadmin/dbconfig-install boolean true | sudo debconf-set-selections
echo phpmyadmin phpmyadmin/app-password-confirm password $PHPMYADMIN_PWD | sudo debconf-set-selections
echo phpmyadmin phpmyadmin/mysql/admin-pass password $MYSQL_PWD | sudo debconf-set-selections
echo phpmyadmin phpmyadmin/mysql/app-pass password $MYSQL_PWD | sudo debconf-set-selections
echo phpmyadmin phpmyadmin/reconfigure-webserver multiselect apache2 | sudo debconf-set-selections
sudo apt -y install phpmyadmin --no-install-recommends
echo ""
echo '##################################'
echo ' Downloading DOMJudge and setup '
echo '##################################'
echo ""
# go to $USERNAME dir
cd /home/$USERNAME
mkdir domjudge
# 1) grep current stable release
MATCH_LINK='<a.*btn-primary.*href="(.*?)"><span.*<\/a>'
LINK=https://www.domjudge.org/$(curl -s https://www.domjudge.org/download | sed -rn "s/$MATCH_LINK/\1/p" | sed 's/^ *//;s/ *$//')
FILENAME=$(echo $LINK | sed -rn "s/.*\/releases\/(domjudge-.*)\.tar\.gz/\1/p")
# 2) grep dev/snapshot release
#MATCH_LINK='.*href=\"(.*\.tar\.gz)\".*'
#LINK=https://www.domjudge.org/snapshot/$(curl -s https://www.domjudge.org/snapshot/ | sed -rn "s/$MATCH_LINK/\1/p" | sed 's/^ *//;s/ *$//')
#FILENAME=$(echo $LINK | sed -rn "s/.*\/.*snapshot\/(domjudge-.*)\.tar\.gz/\1/p")
# download and rename folder
wget $LINK
tar xzf $FILENAME.tar.gz
mv $FILENAME domjudge-files
rm -rf $FILENAME.tar.gz
# configuring domjudge
mkdir /home/$USERNAME/domjudge
cd /home/$USERNAME/domjudge-files
./configure --prefix=/home/$USERNAME/domjudge
# compiling domjudge
make domserver && sudo make install-domserver
make judgehost && sudo make install-judgehost
make docs && sudo make install-docs
echo ""
echo '########################'
echo ' Database installation '
echo '########################'
echo ""
cd /home/$USERNAME/domjudge/domserver/bin
./dj_setup_database genpass
./dj_setup_database -u root -p $MYSQL_PWD install
echo ""
echo '#############################################'
echo '# Adding SSL to our server. #'
echo '# #'
echo '# Note: If no domain is specified, then #'
echo '# this script will generate a #'
echo '# self-signed certificate. Otherwise #'
echo '# will use LetsEncrypt. #'
echo '#############################################'
echo ""
CERT_PEM_FILE=
KEY_PEM_FILE=
if [ -z "$SERVER_DOMAIN" ]; then
echo ""
echo "##################################"
echo "# Domain not found! #"
echo "# Self-signing certificate... #"
echo "##################################"
echo ""
rm -rf /home/$USERNAME/cert/
mkdir /home/$USERNAME/cert/
cd /home/$USERNAME/cert/
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
-days 365 -nodes -subj "/C=MY/ST=Denial/L=Springfield/O=Dis/CN=$IP_ADDR"
CERT_PEM_FILE=/home/$USERNAME/cert/cert.pem
KEY_PEM_FILE=/home/$USERNAME/cert/key.pem
# add self-signed cert into trusted list
sudo ln -s /home/$USERNAME/cert/cert.pem /usr/local/share/ca-certificates/domjudge-selfsigned.crt
sudo update-ca-certificates
else
echo ""
echo "##################################"
echo "# Domain name found! #"
echo "# Lets Encrypt is on its way #"
echo "##################################"
echo ""
sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
cd /opt/letsencrypt
sudo -H ./letsencrypt-auto certonly --apache --non-interactive \
--agree-tos --email $OWNER_EMAIL -d $SERVER_DOMAIN
CERT_PEM_FILE=/etc/letsencrypt/live/$SERVER_DOMAIN/cert.pem
KEY_PEM_FILE=/etc/letsencrypt/live/$SERVER_DOMAIN/privkey.pem
fi
# adding SSL configuration into apache.conf
APACHE_CONF=$(cat <<_EOF_
<VirtualHost *:80>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>
<VirtualHost *:443>
ServerName _default_
DocumentRoot DOMJUDGE_USER_PATH/domjudge/domserver/www
RedirectMatch ^/api$ /api/
Alias /api DOMJUDGE_USER_PATH/domjudge/domserver/www/api/index.php
SSLEngine on
SSLCertificateFile CERT_PEM_FILE_REPLACE
SSLCertificateKeyFile KEY_PEM_FILE_REPLACE
</VirtualHost>
_EOF_
)
# escape forward slash
CERT_PEM_FILE=$(echo "$CERT_PEM_FILE" | sed 's/\//\\\//g')
KEY_PEM_FILE=$(echo "$KEY_PEM_FILE" | sed 's/\//\\\//g')
# replace VARIABLE with appropriate value
APACHE_CONF=$(echo "$APACHE_CONF" | sed "s/DOMJUDGE_USER_PATH/\/home\/$USERNAME/g")
APACHE_CONF=$(echo "$APACHE_CONF" | sed "s/CERT_PEM_FILE_REPLACE/$CERT_PEM_FILE/g")
APACHE_CONF=$(echo "$APACHE_CONF" | sed "s/KEY_PEM_FILE_REPLACE/$KEY_PEM_FILE/g")
echo "$APACHE_CONF" | sudo tee -a /home/$USERNAME/domjudge/domserver/etc/apache.conf
echo ""
echo '###########################'
echo ' Web server configuration '
echo '###########################'
echo ""
sudo rm -rf /etc/apache2/conf-available/domjudge.conf
sudo ln -s /home/$USERNAME/domjudge/domserver/etc/apache.conf /etc/apache2/conf-available/domjudge.conf
sudo a2enmod rewrite
sudo a2enmod ssl
sudo a2enconf domjudge
sudo systemctl stop apache2 && sudo systemctl start apache2
echo ""
echo '#########################'
echo ' Installing judgehost '
echo '#########################'
echo ""
sudo useradd -d /nonexistent -U -M -s /bin/false domjudge-run
sudo groupadd domjudge-run
sudo sed -i "s/domjudge\/api/api/g" /home/$USERNAME/domjudge/judgehost/etc/restapi.secret
sudo sed -i "s/http/https/g" /home/$USERNAME/domjudge/judgehost/etc/restapi.secret
sudo sed -i "s/localhost/$SERVER_DOMAIN/g" /home/$USERNAME/domjudge/judgehost/etc/restapi.secret
sudo ln -s /home/$USERNAME/domjudge/judgehost/etc/sudoers-domjudge /etc/sudoers.d/sudoers-domjudge
sudo sed -i "s/GRUB_CMDLINE_LINUX_DEFAULT=\"\"/GRUB_CMDLINE_LINUX_DEFAULT=\"quiet cgroup_enable=memory swapaccount=1\"/g" /etc/default/grub
sudo update-grub
sudo /home/$USERNAME/domjudge/judgehost/bin/dj_make_chroot
echo ""
echo '##############################'
echo ' Installing React DOMjudge '
echo '##############################'
echo ""
cd /home/$USERNAME/
git clone https://github.com/myungwoo/react-domjudge.git
cd /home/$USERNAME/react-domjudge
npm i
cd client
npm i && npm run build
npm install --save asyncawait
# patch config.js
cd /home/$USERNAME/react-domjudge
NEW_REACT_SECRET=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
sed -r "s/(.*secret.*:.*')(.*?)('.*)/\1$NEW_REACT_SECRET\3/g" config.js > config2.js && mv config2.js config.js
sed -r "s/(.*user.*:.*')(.*?)('.*)/\1root\3/g" config.js > config2.js && mv config2.js config.js
sed -r "s/(.*password.*:.*')(.*?)('.*)/\1$MYSQL_PWD\3/g" config.js > config2.js && mv config2.js config.js
echo ""
echo '#########################################'
echo ' Adding DOMjudge to systemctl service '
echo '#########################################'
echo ""
JUDGEHOST=$(cat <<_EOF_
[Unit]
Description=DOMjudge's judgehost service
After=mysql.service
[Service]
ExecStart=DOMJUDGE_USER_PATH/domjudge/judgehost/bin/judgedaemon
KillMode=process
Restart=always
Type=forking
StandardOutput=syslog
StandardError=syslog
[Install]
WantedBy=default.target
_EOF_
)
JUDGEHOST_CGROUPS=$(cat <<_EOF_
[Unit]
Description=DOMjudge's judgehost cgroup creation service
After=mysql.service
[Service]
ExecStart=DOMJUDGE_USER_PATH/domjudge/judgehost/bin/create_cgroups
KillMode=process
Restart=always
Type=forking
StandardOutput=syslog
StandardError=syslog
[Install]
WantedBy=default.target
_EOF_
)
REACT_DOMJUDGE=$(cat <<_EOF_
[Unit]
Description=DOMjudge with React interface
After=judgehost.service
[Service]
WorkingDirectory=DOMJUDGE_USER_PATH/react-domjudge
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=NODE_PATH server.js
KillMode=process
Restart=always
StandardOutput=syslog
StandardError=syslog
[Install]
WantedBy=multi-user.target
_EOF_
)
NODE_PATH=$(which node | sed 's/\//\\\//g')
# replace constant with its appropriate value
JUDGEHOST=$(echo "$JUDGEHOST" | sed "s/DOMJUDGE_USER_PATH/\/home\/$USERNAME/g")
JUDGEHOST_CGROUPS=$(echo "$JUDGEHOST_CGROUPS" | sed "s/DOMJUDGE_USER_PATH/\/home\/$USERNAME/g")
REACT_DOMJUDGE=$(echo "$REACT_DOMJUDGE" | sed "s/PORT=3000/PORT=$REACT_DOMJUDGE_PORT/g")
REACT_DOMJUDGE=$(echo "$REACT_DOMJUDGE" | sed "s/DOMJUDGE_USER_PATH/\/home\/$USERNAME/g")
REACT_DOMJUDGE=$(echo "$REACT_DOMJUDGE" | sed "s/NODE_PATH/$NODE_PATH/g")
echo "$JUDGEHOST" | sudo tee -a /etc/systemd/system/judgehost.service
echo "$JUDGEHOST_CGROUPS" | sudo tee -a /etc/systemd/system/judgehost_cgroups.service
echo "$REACT_DOMJUDGE" | sudo tee -a /etc/systemd/system/react_domjudge.service
sudo systemctl enable judgehost
sudo systemctl enable judgehost_cgroups
sudo systemctl enable react_domjudge
exit 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment