How to Deploy a Clojure Web Application with Nginx on Ubuntu 20.04
Clojure is a modern, dynamic and powerful programming language on the Java platform. It is based on the LISP programming language and has compilers that make it possible to be run on both Java and .Net runtime environment. Clojure helps you to build systems from the ground up without touching Java code directly. Currently, it is used by many large companies including, Walmart and Puppet Lab.
In this tutorial, we will explain how to deploy a Clojure Web Application on Ubuntu 20.04.
Prerequisites
- A server running Ubuntu 20.04.
- A valid domain name pointed with your server IP.
- A root password is configured the server.
Getting Started
Before starting, it is recommended to update your system packages to the latest version. You can update them with the following command:
apt-get update -y
Once all the packages are updated, install Java and other required packages by running the following command:
apt-get install git curl default-jdk -y
Once all the packages are installed, verify the installed version of Java with the following command:
java -version
You should get the following output:
openjdk version "11.0.9.1" 2020-11-04 OpenJDK Runtime Environment (build 11.0.9.1+1-Ubuntu-0ubuntu1.20.04) OpenJDK 64-Bit Server VM (build 11.0.9.1+1-Ubuntu-0ubuntu1.20.04, mixed mode, sharing)
Once you are finished, you can proceed to the next step.
Install Nginx and Supervisor
Next, you will need to install the Nginx web server and Supervisor to your system. Nginx is a web server used to host application on the internet. Supervisor is a client/server system that allows its users to monitor and control a number of processes on Linux-based operating systems.
You can install both packages with the following command:
apt-get install nginx supervisor -y
Once both packages are installed, you can proceed to the next step.
Download Clojure App
First, you will need to download the Clojure app from the Git repository. You can download it by running the following command:
git clone https://github.com/do-community/do-clojure-web.git
Once the download is completed, you should get the following output:
Cloning into 'do-clojure-web'... remote: Enumerating objects: 37, done. remote: Total 37 (delta 0), reused 0 (delta 0), pack-reused 37 Unpacking objects: 100% (37/37), 6.25 KiB | 399.00 KiB/s, done.
Next, you will need to install Leiningen in your system. Leiningen is a build automation and dependency management tool used for creating projects written in the Clojure programming language. You can download the Leiningen binary package with the following command:
curl https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein -o /usr/bin/lein
Once the download is completed, set the execution permission with the following command:
chmod 755 /usr/bin/lein
Next, change the directory to Clojure and compile the project with the following command:
cd do-clojure-web
lein uberjar
Once the project has been compiled, you should get the following output:
Retrieving commons-codec/commons-codec/1.6/commons-codec-1.6.jar from central Retrieving javax/servlet/servlet-api/2.5/servlet-api-2.5.jar from central Retrieving org/clojure/java.jdbc/0.2.3/java.jdbc-0.2.3.jar from central Retrieving com/h2database/h2/1.3.170/h2-1.3.170.jar from central Retrieving org/eclipse/jetty/jetty-server/7.6.13.v20130916/jetty-server-7.6.13.v20130916.jar from central Retrieving org/eclipse/jetty/orbit/javax.servlet/2.5.0.v201103041518/javax.servlet-2.5.0.v201103041518.jar from central Retrieving org/eclipse/jetty/jetty-continuation/7.6.13.v20130916/jetty-continuation-7.6.13.v20130916.jar from central Retrieving org/eclipse/jetty/jetty-http/7.6.13.v20130916/jetty-http-7.6.13.v20130916.jar from central Retrieving org/eclipse/jetty/jetty-io/7.6.13.v20130916/jetty-io-7.6.13.v20130916.jar from central Retrieving org/eclipse/jetty/jetty-util/7.6.13.v20130916/jetty-util-7.6.13.v20130916.jar from central Retrieving medley/medley/0.5.3/medley-0.5.3.jar from clojars Retrieving clout/clout/2.1.0/clout-2.1.0.jar from clojars Retrieving compojure/compojure/1.3.1/compojure-1.3.1.jar from clojars Retrieving ring/ring-core/1.3.2/ring-core-1.3.2.jar from clojars Retrieving instaparse/instaparse/1.3.4/instaparse-1.3.4.jar from clojars Retrieving crypto-random/crypto-random/1.2.0/crypto-random-1.2.0.jar from clojars Retrieving crypto-equality/crypto-equality/1.0.0/crypto-equality-1.0.0.jar from clojars Retrieving clj-time/clj-time/0.6.0/clj-time-0.6.0.jar from clojars Retrieving ring/ring-codec/1.0.0/ring-codec-1.0.0.jar from clojars Retrieving ring/ring-defaults/0.1.2/ring-defaults-0.1.2.jar from clojars Retrieving ring/ring-ssl/0.2.1/ring-ssl-0.2.1.jar from clojars Retrieving ring/ring-headers/0.1.1/ring-headers-0.1.1.jar from clojars Retrieving ring/ring-anti-forgery/1.0.0/ring-anti-forgery-1.0.0.jar from clojars Retrieving hiccup/hiccup/1.0.2/hiccup-1.0.2.jar from clojars Retrieving ring/ring-jetty-adapter/1.3.2/ring-jetty-adapter-1.3.2.jar from clojars Retrieving ring/ring-servlet/1.3.2/ring-servlet-1.3.2.jar from clojars Compiling do-clojure-web.handler Created /root/do-clojure-web/target/do-clojure-web-0.1.0.jar Created /root/do-clojure-web/target/do-clojure-web-0.1.0-standalone.jar
Once you are finished, you can proceed to the next step.
Create Directory Structure for Clojure Application
Next, you will need to create a directory structure for the Clojure app and place required files and directory to a specific location.
First, create a directory structure with the following command:
mkdir -p /var/www/html/do-clojure-web/app/db
Next, copy your Clojure app and database to the specific directory with the following command:
cp /root/do-clojure-web/target/do-clojure-web-0.1.0-standalone.jar /var/www/html/do-clojure-web/app/
cp /root/do-clojure-web/db/do-clojure-web.h2.db /var/www/html/do-clojure-web/app/db/
Next, set proper permissions and ownership with the following command:
chown -R www-data:www-data /var/www/html/do-clojure-web/
chmod -R 775 /var/www/html/do-clojure-web/
Next, change the directory to the Clojure app and create a symbolic link of your clojure application:
cd /var/www/html/do-clojure-web/app/
ln -s do-clojure-web-0.1.0-standalone.jar do-clojure-web.jar
Next, verify whether your application is working or not by running the following command:
java -jar do-clojure-web.jar
If everything is fine, you should get the following output:
2020-11-25 10:19:51.456:INFO:oejs.Server:jetty-7.x.y-SNAPSHOT 2020-11-25 10:19:51.497:INFO:oejs.AbstractConnector:Started [email protected]:5000
Once you are finished, you can proceed to the next step.
Configure Supervisor for Clojure Application
There are several ways to manage the Clojure application as a service. In this tutorial, we will use Supervisor for managing the Clojure app. You can configure it by creating a file inside the Supervisor configuration directory:
nano /etc/supervisor/conf.d/do-clojure-web.conf
Add the following lines:
[program:do-clojure-web] command=/usr/bin/java -jar do-clojure-web.jar directory=/var/www/html/do-clojure-web/app user=www-data autostart=true autorestart=true startretries=3 redirect_stderr=true stdout_logfile=/var/log/do-clojure-web.app.log
Save and close the file then restart the Supervisor service to apply the changes:
systemctl restart supervisor
Next, enable the Supervisor service to start at system reboot:
systemctl enable supervisor
You can now verify the status of the Supervisor with the following command:
systemctl status supervisor
You should get the following output:
? supervisor.service - Supervisor process control system for UNIX Loaded: loaded (/lib/systemd/system/supervisor.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2020-11-25 10:22:31 UTC; 1min 12s ago Docs: http://supervisord.org Main PID: 40927 (supervisord) Tasks: 28 (limit: 2353) Memory: 104.6M CGroup: /system.slice/supervisor.service ??40927 /usr/bin/python3 /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf ??40946 /usr/bin/java -jar do-clojure-web.jar Nov 25 10:22:31 ubuntu2004 systemd[1]: Started Supervisor process control system for UNIX. Nov 25 10:22:31 ubuntu2004 supervisord[40927]: 2020-11-25 10:22:31,603 CRIT Supervisor is running as root. Privileges were not dropped becaus> Nov 25 10:22:31 ubuntu2004 supervisord[40927]: 2020-11-25 10:22:31,603 INFO Included extra file "/etc/supervisor/conf.d/do-clojure-web.conf" d> Nov 25 10:22:31 ubuntu2004 supervisord[40927]: 2020-11-25 10:22:31,608 INFO RPC interface 'supervisor' initialized Nov 25 10:22:31 ubuntu2004 supervisord[40927]: 2020-11-25 10:22:31,608 CRIT Server 'unix_http_server' running without any HTTP authentication > Nov 25 10:22:31 ubuntu2004 supervisord[40927]: 2020-11-25 10:22:31,609 INFO supervisord started with pid 40927 Nov 25 10:22:32 ubuntu2004 supervisord[40927]: 2020-11-25 10:22:32,612 INFO spawned: 'do-clojure-web' with pid 40946 Nov 25 10:22:33 ubuntu2004 supervisord[40927]: 2020-11-25 10:22:33,615 INFO success: do-clojure-web entered RUNNING state, process has stayed >
At this point, Supervisor service is started and your application is listening on port 5000. You can check it with the following command:
ss -antpl | grep 5000
You should get the following output:
LISTEN 0 50 [::ffff:127.0.0.1]:5000 *:* users:(("java",pid=40946,fd=7))
Once you are finished, you can proceed to the next step.
Configure Nginx for Clojure Application
Next, you will need to configure the Nginx as a reverse proxy to serve the Clojure app. First, create an Nginx virtual host configuration file with the following command:
nano /etc/nginx/sites-available/clojure.conf
Add the following lines:
upstream http_backend { server 127.0.0.1:5000; keepalive 32; } server { listen 80; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name clojure.example.com; location / { proxy_pass http://http_backend; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; access_log /var/log/do-clojure-web.access.log; error_log /var/log/do-clojure-web.error.log; } }
Save and close the file when you are finished. Then, enable the Nginx virtual host with the following command:
ln -s /etc/nginx/sites-available/clojure.conf /etc/nginx/sites-enabled/
Next, verify the Nginx for any syntax error with the following command:
nginx -t
You should get the following output:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Finally, restart the Nginx service to apply the changes:
systemctl restart nginx
Once you are finished, you can proceed to access the Clojure app.
Access Clojure Application
Now, open your web browser and access the Clojure application using the URL http://clojure.example.com. You should see the Clojure application dashboard in the following screen:
Click on the Add a Location button. You should see the following screen:
Provide your desired values and click on the submit location button. You should see the following screen:
Now, click on the View All Locations button. You should see your added location in the following screen:
Conclusion
Congratulations! you have successfully deployed the Clojure app with Nginx as a reverse proxy on Ubuntu 20.04 server. You can now try to deploy your custom application with Clojure.