Last active
July 19, 2023 14:31
-
-
Save shahril96/64f7eeeaa6c1a0856f14105e5ce149dc to your computer and use it in GitHub Desktop.
A helper script to automatically setup a DOMjudge server in 10 minutes, go get yourself a coffee.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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