The lein-ring
plugin can create 2 different types of packages for deployment: an uberjar
or an uberwar
. These are created using lein ring uberjar
or lein ring uberwar
respectively:
.jar
file containing all dependencies, including an embedded Jetty server.war
file containing all dependencies, which can be deployed to any Java web application server (such as Tomcat or GlassFish)Check out the official lein-ring documentation to get more details about the various options available for ring uberwar/uberjar
at https://github.com/weavejester/lein-ring.
How you're going to deploy your application determines how you're going to package your application.
Because Ring applications have an embedded Jetty server, we have the option of creating a self-contained, fully independent uberjar, which contains all the required dependencies and can run on its own. The advantage of this is that deployment becomes dead simple – you simply copy the uberjar to a server and run it as you would any other Java application (we'll do this later in the chapter). If we want another instance of our app, we can simply fire it up like any other Java app – Ring will automatically determine which port to serve on (starting at 3000 and going up from there).
Running as an uberjar has some drawbacks though: You don't get a fancy administrative console like you do with a Java application server, which means that you'll be rolling a lot of configuration by hand. The standalone uberjar is pretty barebones, but in the world of web applications, rarely have I worked on anything that actually required all the functionality that's embedded inside an application server.
If you plan on deploying to an application server, then you'll need to package the application as an uberwar.
Application servers provide a whole truckload of features, such as queuing, configuration management, clustering (though we can use Nginx and multiple instances of a standalone server to accomplish this), and so on. Most application servers allow you to configure their features through a UI (though in my experience these are often clunky). Some application servers, such as GlassFish, are free and open source. Others, however, such as WebSphere and WebLogic, cost an arm and a leg.
The downsides of application servers are cost and, often times, bloated. They can be fairly resource intensive, expensive, and complicated. Also, chances are you aren't going to need an application server; in the world of Clojure web application development, I've yet to write anything that requires the golden handcuffs of an application server. Most Clojure web applications are deployed as a standalone application.
The easiest way to deploy a Ring application is as a standalone application, and just use the embedded Jetty server. This is the killer feature as far as I'm concerned. To create a standalone hipstr application, perform the following steps:
lein ring uberjar
. This produces 2 jars:./target/hipstr-0.1.0-SNAPSHOT.jar
: Contains all our hipstr application code and dependencies../target/hipstr-0.1.0-SNAPSHOT-standalone.jar
: An executable, standalone version which includes an embedded Jetty server and all dependencies. This is entirely self-contained../target
directory (keeping in mind that we can use Java system properties to set the environment configuration, such as the -D
Java system properties below):# java -jar -Ddb.classname=org.postgresql.Driver -Ddb.subprotocol=postgresql -Ddb.subname=//localhost/postgres -Ddb.user=hipstr -Ddb.password=p455w0rd hipstr-0.1.0-SNAPSHOT-standalone.jar
As is the case with the development server, the above command will serve on port 3000. Also like the development server, the above command will execute in the foreground, which you can stop by hitting Ctrl + C, or by shutting down the terminal. However, in a non-dev/local environment you'll want to run the application in the background, which can be done by using nohup
:
# nohup java -jar -Ddb.classname=org.postgresql.Driver -Ddb.subprotocol=postgresql -Ddb.subname=//localhost/postgres -Ddb.user=hipstr -Ddb.password=p455w0rd hipstr-0.1.0-SNAPSHOT-standalone.jar &
This will persist the application after you close down the terminal. To stop the application, you first get the process ID using ps -ef
, and then kill -15
that process:
# ps -ef | grep hipstr >> 501 68443 58530 0 6:07pm ttys000 0:09.00 /usr/bin/java -jar... # kill -15 68443
Keep in mind that you can export environment variables (using "_"
instead of ".
", such as using DB_CLASSNAME
instead of db.classname
) if you don't want to use Java system properties. However, this will force every instance of the hisptr application on that machine to have the same database connection. You'll have to decide which makes more sense.
Nginx is quickly becoming a popular web-server/reverse-proxy. Its configuration is relatively simple and clean compared to the now-dated Apache. And it's fast. Blisteringly fast. Scary fast!
We can use Nginx to reverse-proxy port 80 to our hipstr application's port 3000 by performing the following steps:
# mv /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak
nano
because I've never bothered to learn vi
. Blasphemy, I know):# nano /etc/nginx/sites-available/default
[::]
wildcard:server { # listen on port 80, but apply this explicitly to # only the default server listen 80 default_server; # only allow IPv6 socket to process # IPv6 connections listen [::] 80 default_server ipv6only=on; # specify a "catch-all"; any host name on port 80 # will be affected. server_name _; # log files access_log /var/log/hipstr_access.log; error_log /var/log/hipstr_error.log; # proxy settings location / { # proxies all requests under "/" to # our hipstr standalone instance proxy_pass http://localhost:3000/; # forwards the original Host header proxy_set_header Host $http_host; # forwards the X-Forwarded-For client # request header, if it exist, # as well as the client's remote # address (IP), separated by a comma. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # forwards the original protocol # (eg. https or http) # in the real world you'd likely want # to do SSL termination, and setup # whatever's hosting the hipstr # standalone to only trust incoming # traffic from the fronting nginx's # IP. proxy_set_header X-Forwarded-Proto $scheme; # cancel the effect of all # proxy_redirect directives proxy_redirect off; } }
# nginx -s reload;
Now whenever you hit up port 80, instead of explicitly stating port 3000, you'll get our hipstr application.
Using Nginx, we can easily proxy multiple hipstr applications by employing a round-robin approach between all of them:
/etc/nginx/sites-available/default
to edit it.server {...}
block, add the following:upstream hipstr { server localhost:3000; server localhost:3001; server localhost:3002; }
proxy_pass
in the location /
configuration section of the server
block so that it looks like the following:location / { # proxies all requests under "/" to # our hipstr standalone instance proxy_pass http://hipstr;
# nginx -s reload
nohup
command.That's all there is to it! You are now running a round-robin balanced cluster of hipstr applications! How easy was that!
3.147.59.198