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:

Access Clojure Application

Click on the Add a Location button. You should see the following screen:

Add Location

Provide your desired values and click on the submit location button. You should see the following screen:

CRUD

Now, click on the View All Locations button. You should see your added location in the following screen:

Result

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.

Share this page:

0 Comment(s)