Deploying Web Apps

by Robert Pastel, Mark Woodford and Travis Forester

Deploying a web app is fundamentally the operation of packaging the files in your development environment and uploading the package to the server, but there are details of the application that you will need to attend to so that your application runs properly on the server. In particular you will need to:

  • Configure the database for operation on the server
  • Configure mail service to run on the server
  • Configure any file paths that might differ between development and production
  • Package your application into a WAR
  • Upload the WAR to a server and check that it is running properly

Terminology

I need to introduce some terminology before we can configure and deploy of your applications. Grails can be configured to run differently in different “environments.” See

https://grails.org/wiki/environments

http://grails.github.io/grails-doc/latest/guide/conf.html#environments

Grails has basically three different environments:

  • development
  • test
  • production

Typically the development environment is the environment while you are programming on your computer at home. The production environment is typically a server that is accessed by the public. The test environment could be on a server that is setup to test integration of many services and web apps. Although, a development process should proceed from the development environment to the test environment and then finally made public in the production environment, we will shorten the process and use only the development and production environment. This implies that you will do final testing in the production environment.

The second term to discuss is the “WAR.” WAR stands for “Web application ARchive.” It is basically a JAR file that has a specific directory structure for web applications.

http://en.wikipedia.org/wiki/WAR_(file_format)

In Java Server Page (JSP) technology, deployment proceeds by making a WAR file of your application and uploading the WAR file to a special directory on the server. The server un-packages the WAR, called exploding, knows how to interpret the files in your applications, and consequently can serve the files to the public. There are several JSP servers, see the list at Wikipedia

http://en.wikipedia.org/wiki/JavaServer_Pages

We will be using the Apache Tomcat server

http://en.wikipedia.org/wiki/Apache_Tomcat

Realize that Tomcat is in essences just a Java application. There is no special hardware associated with the server, but for the server to be public it needs be connected to the Internet and registered in a Domain Name Server (DNS).

OK, that is enough terminology for now.

Configure the database for operation on the server

When developing a Grails application, there are a number of database options available. You may choose to use H2 (default), HSQLDB, MySQL, etc. In addition, you can choose how the database will be stored:

  • hosted on a server: a service such as mysqld, running separately from the web application and possibly on a different machine, handles requests from the application to create, read, update, or delete data within the database
  • embedded: the database is located within the application itself, and all operations to the database are done directly by the application

For rapid prototyping, and for use cases in which the database accessed relatively infrequent  (i.e. there are only a few connections at once) an embedded database will work just fine. For small projects, embedded databases have the advantage of being easy to initialize and maintain.

Another design choice is whether to have the database stored on disk or in memory. If the database is expected to grow very large, then it would be better to store the database files on disk to prevent out-of-memory errors. Keeping the database in memory allows faster access times, but if something goes wrong, all data in memory will be lost. So, it makes sense that during development you would like to use a database that is stored in memory, so that you can quickly make and use the database. But during production you would like the database to be stored on the disk so that the data will persist between stopping and starting the web application.

I now explain how to configure your Grails application to connect to an embedded H2 database stored on disk.

Open the DataSource.groovy configuration file.

Direct your attention to the dataSource settings at the beginning of the file. The property driverClassName should be “org.h2.Driver”. Also, note that the username and password for the database are defined here.

Now locate the environment-specific settings. You should see code structure as below

environments {
    development {
        dataSource {
            …
        }
    }
    test {
        dataSource {
            …
        }
    }
    production {
        dataSource {
           dbCreate = "update"
           url = …
           properties {
                …
           }
        }
    }
}

Grails allows you to configure specific settings for development, testing, and production environments. I suggest leaving the development and testing settings how they are. In the production settings, just above the url, insert the following line:

dbdir = "${System.properties['catalina.base']}/db/${appName}"

Lastly, modify the connection url to be:

url = "jdbc:h2:file:${dbdir};MVCC=TRUE;LOCK_TIMEOUT=10000"

Save the changes to DataSource.groovy. Now your Grails application is configured to connect to an on-disk H2 database at the filepath specified on the tomcat server. Now when you deploy your application (as a WAR file) to the tomcat server, a new H2 database with the given name will be created (if it doesn’t already exist).

For more details about how to configure the data source see the grails documentation

http://grails.github.io/grails-doc/latest/guide/conf.html#dataSource

and for a summary on how data source is configured by environments

http://grails.github.io/grails-doc/latest/guide/conf.html#dataSourcesAndEnvironments

Problems with Database?

Please try the above instructions first. Skip to the “Configure mail service to run on the server” section and continue reading. Do not read this section until after you have tried deploy and have problems.

If you have problems with deployment, check your server logs. If the logs suggest that problem is with the database creation, first check your server directory. Check that the directory db/ directory is created with a file located in it:

 /usr/share/tomcat_team<number>_<year>01/db/

where

  • <number> is your team number
  • <year> is the year of the class

If the db/ directory is not created. Try creating the db/ directory and redeploying. If deployment problem still exist try hard coding the path to the database. Replace the “dbdir” assignment to:

dbdir = "/usr/share/tomcat_team<number>_<year>01/db/<appname>"

Where

  • <number> is your team number
  • <year> is the year of the class
  • <appname> is the name of your app

If you are team 2 during the year 2016 making the app called DearWithIt, then the line should be:

dbdir = "/usr/share/tomcat_team2_2016501/db/DearWithIt"

This hardcode a filepath for the destination of the on-disk database. It will create a db/ directory and add the database file named with your app name. Please read more about how the filepath is specified in the section below called “App Base”.

Configure mail service to run on the server

If your web application uses a mail service then you will need to configure it for the production mail server. If your application requires users to register in order to use the app then your web app should be using the mail server to send a key to the user’s email address so that they can finish the registration. This is done for two reasons. The email address is a unique identifier for the user. Also, responding to the email address assures that the user is a “real” person and not a robot because a real user can click on the url specified in email. Finally the mail service is used to send a key to the user when they forget their passwords and need to reset their passwords. If you are using Spring Security UI plugin in your application then the above registration and forgotten password procedures are implement in your web app, and your web app is using a mail server and the Grails Mail plugin.

By default the Mail plugin is configured at localhost on port 25. The Mail plugin can be reconfigured in Config.groovy file. On the production server your application will use a special mtu email account. The email address is “mushroommailer@mtu.edu”  with a password I’ll give you later. In the bottom of the Config.groovy file add the following code:

// Spring Security Email Configurations
grails {
    	mail {
        		host = "smtp.gmail.com"
        		port = 465
        		username = "mushroommailer@mtu.edu"
        		password = "actual-password"
        		props = ["mail.smtp.auth":"true",
            			"mail.smtp.socketFactory.port":"465",
            			"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
            			"mail.smtp.socketFactory.fallback":"false"]
     }
}

Note that you will have to replace “actual-password” with a password that I will give you via google docs.

You can read more about configuring and using the Mail plugin at

http://grails.org/plugins/mail

Configure any file paths that might differ between development and production

I suspect that most of the teams can skip this step. Meaning your production application is not using different file paths from your development paths. This is because you are storing uploaded files as blobs in the database. But sometimes databases are setup to store only the file path to the uploaded file rather than the complete file. If your database is configured like this then the file paths will be different on the development machine then on the production server. Below is technique to make it convenient to have different file paths.

This is an example of the solution used to determine the photo upload location in the Mushroom Mapper app.

A json file in the project (specifically, MushroomMapper/web-app/text/photo_cfg.json) contains internal and external paths to use for the upload location, for both development and production environments:

{
   "production": {
   		     "server": "/itss/local/home/cittemp/public_html/photos/",
   	     	"client": "/photos/"
 	 },
  	"development": {
        		"server": "web-app/images/photos/",
       		 "client": "/MushroomMapper/images/photos/"
 	  }
}

This file makes it easy to find and change the paths if necessary, without delving into the code.

A function called initPhotos parses this file, and sets the current server and client variables depending on the current environment context. This function can be a method of a controller.  In the case of mushroom mapper it is a method of the main controller, ObservationsController.groovy. The variables set by the function are servletContext.photos.server and servletContext.photos.client.

void initPhotos() {
    def txt = servletContext.getResourceAsStream('text/photo_cfg.json')
    def cfg = new JsonSlurper().parseText(txt.getText())
    if (Environment.current == Environment.PRODUCTION)  
         servletContext.photos = cfg.production
    else servletContext.photos = cfg.development
}

The ‘servletContext’ variable (which is the ‘application’ variable when used in a gsp) behaves as a map whose data persists across all requests and sessions, so this function only needs to be called once for the lifetime of the server. Therefore, the following line is at the start of each action/method of the controller that uses these variables:

if (servletContext.photos == null) initPhotos()

‘photos.server’ is the internal path to the photos directory, and should be used with Groovy File objects, etc. ‘photos.client’ is the external uri, and should be used in the html, javascript, etc.

Naturally, the user running the server should have +rwx permissions on the directory in question.

Package your application into a WAR

Packaging your application into a WAR only requires that the WAR file is named properly and that it is built for the correct environment. The WAR should be built for the production environment before uploading it to the production server.

The WAR is named in BuildConfig.groovy configuration file. In the BuildConfig.groovy, uncomment the war.file specification. It is near the top of the file, and edit it so that it looks like

grails.project.war.file = "target/${appName}.war"

Note we do not want the version number included in the war file name. The WAR file name must match the project name or the web app will not deploy properly. You can edit the WAR file name if you want without hurting the contents.  Once your have configured the WAR name properly, you’ll not have to do this again.

To make the WAR file you run a grails command. You’ll need to do this step each time you want to deploy a new version of your web application. On your development machine, your home machine, make the war file in production environment mode. Production environment is the default for the “war” command but not for the “run-war” command. The command executed in your project directory is simply

grails war

The build and compression will take several minutes. You will find the WAR file in your project’s target/ directory.

Uploading the WAR to your Server and Insure it is running

Tomcat servers have a special directory called the appbase. The WAR files are uploaded to the appbase directory and then tomcat will expand/explode the WAR file in the directory. This deploys the web application. If there is already a WAR file with the same name then the old WAR file should be deleted before uploading the new WAR file. Tomcat will detect that the WAR file is deleted and delete the corresponding exploded web application. This is called undeploying. You must undeploy before redeploying.

Because Tomcat is just a Java application, the machine running Tomcat can have multiple instances of Tomcat. In order that the Tomcat servers do not interfere with each other while serving pages, the different instances of the Tomcat server are configured to receive their request and send their responses through different port numbers. Recall that while you were programming and testing your individual assignments you would point your browser to the URL

http://localhost:8080/cs4760progassign/
  • http: – represents the protocol, in this case hypertext transfer protocol
  • localhost – is the domain name for the server, in this case it means the current machine
  • 8080 – is the port number

Each team in the class has their own instance of Tomcat to use for deployment. But each Tomcat will be listening and sending to a different port.

Domain

The domain name for the machine with the tomcat instances is

cshci-dev.mtu.edu

AppBase

To deploy your  WAR file you need to know the appbase for your tomcat instances. The appBase for the tomcat intstances for each teams are at

  • /usr/share/tomcat_team1_201501/webapps/
  • /usr/share/tomcat_team1_201501/webapps/
  • /usr/share/tomcat_team3_201501/webapps/

In other words the directory for the different tomcat instances have the format that specifies the <team-number>, <year> and <semester>. Team number is the your team number in the course.

tomcat_team<team-number>_<year><semester>

The spring semester is <semester> = 01

The year for 2015 is <year> = 2015. For the year 2016 it will be <year> = 2016, etc

Each team has access only to their tomcat instance’s directories. If your explore your tomcat directories your should find the logs/ directory.  You may need to study the log files if you have errors after deploying. The log file that the errors will printed in are the catalina.***.log. A new log file is created each day. You find most recent entry in the log file you scroll to the bottom of the log file.

Port Numbers

As mention above each tomcat instance is configured to listen on a different point.

  • tomcat_team1 listens on port 8081
  • tomcat_team2 listens on port 8082
  • tomcat_team3 listens on port 8083
  • etc.

The general form of the port numbers is

808<team-number>

Where <team-number> is your course team number.

So, when you check your deployed web application, each team will have to use their own port number. Team 1 would point their browser to

cshci-dev.mtu.edu:8081/team-1-app-name

where “team-1-app-name” is the app name that team one has for their web application. Team 2 would point their browser to

cshci-dev.mtu.edu:8082/team-2-app-name

etc.

Special Note about the number of WAR files

JSP and especially Grails web applications use lots of memory. They can also have a memory leak if they are not redeployed properly. The tomcat instances for the class have enough memory for only one additional web applications besides the web application that comes standard with tomcat.

In your appbase you’ll notice that there are already some directories which are web applications. They are:

  • default/ – web app for bare domain
  • docs/ – documents for how to use tomcat
  • examples/ – example web applications
  • host-manager/ – web app for managing domain name
  • manager/ – web app for managing web apps

Leave these web apps in your appBase. They do not consume much memory. You can access default, docs, and examples through your browser, and you should do so to check that your tomcat instances is running properly. You need a login to access the host-manager and the manager web app.

Remember: ONLY add one more web app to your appBase, otherwise your tomcat might run out of memory and crash.

Uploading and Deploying

Using a SFTP client (WinSCP is a very good choice for Windows) login into the Tomcat machine. (See domain name above.) I highly recommend that you use RSA keys so that the client can auto log in during network distributions. If you are logging into the server from a machine not on MTU network then you need to use a virtual network (VPN) with mtu. Point a browser to

vpn.mtu.edu

Log in and then select “Standalone VPN client”. This will download “BIGIPEdgeClient.exe”. Run this executable file in admin mode, and it will install the “BIG-IP Edge Client” to your apps. You run the client and click the “connect button.” A window will pop up asking for your username and password. After clicking the logon button, the VPN is created. You need to keep the app running while use your SFTP client to upload files to the server. If you do not have a VPN connection, you’ll get an “network error” and not be able to connect.

In the SFTP client, navigate to the appBase. (See above for the appBase directory.)

If you have previously deployed a WAR file for your web app that you are currently deploying then it should still exist in the appBase alongside the exploded web app. The exploded wep app is a directory with the same name as the WAR file. Delete the old WAR in the appBase before uploading the new WAR.

Wait. Wait until Tomcat deletes the old exploded web app. If you do not wait then deployment will fail, and Tomcat will never explode the new WAR file.

When the old web app directory disappears, use your SFTP client to upload the new WAR file.

Wait. Sometimes Tomcat takes several minute, up to 10 minutes, to see the new WAR file and explode it.

Point your browser to the web app and inspect it. (See above for port number.)

Something Goes Wrong

The above procedure can go wrong. Some typically difficulties are

  1. The database lockfile is not deleted during redeployment
  2. The exploded web application is not deleted during redeployment
  3. Memory overflow locking or crashing the server

You can determine the cause of your problems by inspecting the log files. In most cases stopping and starting tomcat will solve your problems. Sometimes you may need to delete the offending file or directory, e.g. the lockfile in the db/ directory.

You have access to a few commands that are normally run by the root user. These commands are called sudo commands and are proceed by “sudo.”

There are four commands

  • start – to start tomcat
  • stop – to spot tomcat
  • restart – to stop and start
  • status – to check tomcat status

The frequently used commands are stop and start. You first stop tomcat then delete or inspect your files and finally you start tomcat again. After starting tomcat you can make a fresh deployment.

Team 1 would run commands

sudo service tomcat_team1 stop
sudo service tomcat_team1 start

Team 2 would use commands

sudo service tomcat_team2 stop
sudo service tomcat_team2 start

etc.

Good luck