DNS and IP
One thing you’ll have to decide is how your server will be found. An Amazon EC2 instance gets an IP address and a DNS name based on this assigned by Amazon. While this may be used access the instance, there are some drawbacks: the names won’t be easy to remember and the IP address is volatile in the sense that if you terminate the server and start a new one to replace it, you won’t be able to get the same IP address back.
To fix this, you might use an Amazon EC2 load balancer (also included in the free tier). According to the instructions, you should link this to some domain name you own by using a CNAME record, having the DNS name you actually want to use point to the DNS name of the load balancer. This didn’t really work out for me, it seemed to introduce delays and inconsistent results.
I decided to use an Amazon EC2 Elastic IP address, which is like a static IP address that you can assign to instances you own at your liking. At a DNS-server outside Amazon, I just used an A-record to have my DNS name point to that IP address. This works fine. These Elastic IP addresses are free as long as you use them for an instance, you only pay a small fee if you keep them ‘in stock’.
Launching the instance
I start with launching an instance with the ‘Amazon Linux AMI 2012.03′ image, 64-bit, of the micro-instance type. Instance details can be left at their defaults. I authenticate using a key-pair, first time you’ll have to generate it and store the .pem file to you’re local computer.
To configure the firewall, I would recommend creating a security group ‘jboss-devel’ or something (if you go with the default ‘quick-start-1′ you won’t be able to change that later, and it’s a meaningless name). Security requirements may vary, but I choose to open up port 80 (http to Apache httpd) to everyone (0.0.0.0/0) and port 22 (ssh), 5432 (PostgreSQL), 8080 (http to JBoss AS) and 9990 (http to JBoss AS management) only to specific IP addresses at home and at work (enter the IP address plus /32 in the firewall list). You may open these ports to the entire Internet for easier administration, but it does increase security risk. Below, I’ll assume that you have at least opened them for your own local workstation, so you can use your local browser for JBoss AS management and a local pgAdmin tool to access the database.
After completing the wizard the instance will launch and be up and running in just a few minutes (refresh the instance list and watch the ’status checks’). Then, you can assign the Elastic IP to the instance through the Elastic IP overview.
Getting access to your instance
You can use any SSH-client, for instance Bitvise Tunnellier. Login to your server with user “ec2-user” and the downloaded keypair as the authentication method. This should get you a prompt (after accepting the server’s keypair).
The first thing you should do is apply security updates by issuing the command
sudo yum update
(this is easy, the welcome message already says you should).
Installing Apache
We will set up an Apache httpd in front of our JBoss AS instance. This has several benefits, most important one being security. It will allow users to access you application on the standard port 80, without JBoss AS having to run as root.
Apache httpd is in of the standard repositories of the EC2 instance, so you may just install it by entering
sudo yum install httpd.x86_64
To make sure it starts automatically, and run it right now as well, enter the following:
sudo chkconfig --level 345 httpd on sudo /etc/rc.d/init.d/httpd start
If you now access your instance through a browser, you should be able to see the ‘Amazon Linux AMI Test Page’.
Installing JBoss AS
JBoss AS is not available as a standard package that you can install using ‘yum’. Instead, download the 7.1.1.Final tarball from JBoss and copy it to your instance (home directory of ec2-user is fine).
For security purposes, JBoss should run under its own user-id. On this devel-machine, I also want my ec2-user to be able to modify the JBoss file (in particular deployments). Therefore, I’ll setup a jboss-as group and jboss-as user, and also make the ec2-user member of the jboss-as group:
sudo groupadd jboss-as sudo useradd -g jboss-as jboss-as sudo usermod -a -G jboss-as ec2-user
Terminate your ssh session and log in again, this will ensure you are in the right group. Next, we’ll unpack the tarball and set-up some permissions, ownership, and a symbolic link:
sudo tar xzf jboss-as-7.1.1.Final.tar.gz -C /usr/share sudo ln -s /usr/share/jboss-as-7.1.1.Final /usr/share/jboss-as sudo chown -R jboss-as:jboss-as /usr/share/jboss-as-7.1.1.Final sudo chmod -R 775 /usr/share/jboss-as-7.1.1.Final
Of course, we would like to run JBoss AS as a regular init.d service, just like Apache httpd. Fortunately, the scripts are already in the distribution, we just have to create some directories, do some copying and run ‘chkconfig’:
sudo mkdir /var/run/jboss-as sudo chown jboss-as:jboss-as /var/run/jboss-as sudo mkdir /var/log/jboss-as sudo chown jboss-as:jboss-as /var/log/jboss-as sudo mkdir /etc/jboss-as sudo ln -s /usr/share/jboss-as/bin/init.d/jboss-as.conf /etc/jboss-as/jboss-as.conf sudo ln -s /usr/share/jboss-as/bin/init.d/jboss-as-standalone.sh /etc/init.d/jboss-as sudo chkconfig --add jboss-as sudo chkconfig --level 345 jboss-as on
To have JBoss listen on all public interfaces, edit standalone.xml in /usr/share/jboss-as/standalone/configuration (use ‘sudo vi’ or something), and edit the interface definitions to use address 0.0.0.0 instead of the default (I’ve underlined what is changed/added):
<interface name="management"> <inet-address value="0.0.0.0"/> </interface> <interface name="public"> <inet-address value="0.0.0.0"/> </interface>
Also, I recommend increasing the deployment-timeout to 5 minutes by adding this value to the deployment-scanner configuration:
<subsystem xmlns="urn:jboss:domain:deployment-scanner:1.1"> <deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000" deployment-timeout="300"/> </subsystem>
This is not always necessary, but the performance of the micro-instance is a bit unreliable en you might get deployment timeouts if you don’t set this value.
In /etc/jboss-as/jboss-as.conf, you should remove the comment-sign before the configuration of JBOSS_USER.
By running /usr/share/jboss-as/bin/add-user.sh, you can add a management user in the ManagementRealm that will be able to log in to the JBoss management console.
Now, we’re ready to start JBoss AS:
sudo /etc/rc.d/init.d/jboss-as start
You should be able to access the server through your browser on port 8080, and login on the management console with the user you created.
Upgrading to Java SE 7
Since Java SE 6 will be end of life in November 2012, just 5 months in the future at the time of writing, I prefer to upgrade to Java SE 7. This is not a standard yum install either. Start with downloading jdk-7u4-linux-x64.gz from Oracle and copy it to your EC2 instance. Unpack to the JVM directory:
sudo tar xzf jdk-7u4-linux-x64.gz -C /usr/lib/jvm sudo chown -R root:root /usr/lib/jvm/jdk1.7.0_04/ sudo ln -s /usr/lib/jvm/jdk1.7.0_04 /usr/lib/jvm/java
Now, edit /etc/java/java.conf and uncomment the line:
JAVA_HOME=$JVM_ROOT/java
Restart JBoss AS:
sudo /etc/rc.d/init.d/jboss-as restart
Through the Jboss AS management console/configuration/environment properties, you should be able to verify that you’re using the Java 7 JVM. In my experience, this doesn’t work if you leave out the symbolic link /usr/lib/jvm/java and point directly to the install dir, but I don’t understand why this is.
Deploying the first application
To continue our configuration, its useful to have some test-application deployed. On the JBoss AS download page, you can find the jboss-as-quickstarts that are perfect for that. You can build these application on you development station with a Maven 3/Java 7 environment, just using mvn package. (There is no need to import this into Eclipse or another IDE.)
I choose to use the ‘hibernate4’ example. This example has an internal unmanaged datasource. We’ll first deploy it as-is, then we’ll make it available through the Apache httpd, and after that we’ll hook it up to an actual PostgreSQL database.
The Maven build should result in a file jboss-as-hibernate4.war in the target directory. You may deploy this through the web console, but personally I prefer a simple copy to /usr/share/jboss-as-7.1.1.Final/standalone/deployments. JBoss AS will create small files in that directory to give you feedback on the deployment. You should end up with a ‘jboss-as-hibernate4.war.deployed’ file. You should be able to access this application using your browser on port 8080 and context path /jboss-as-hibernate4. I should show a demo ‘member registration page’, and you should be able to register a new member.
Setting up Apache httpd as a reverse proxy
Apache httpd could be configured as a standard http proxy to JBoss AS, but that has a number of drawbacks. There is a performance hit and the server will loose information about the client. Since I do a lot of SOAP-webservices stuf, another important drawback for me is that it introduces difficulties when JBoss AS serves WSDLs. Therefore, we’ll use the binary AJP protocol. First, we’ll enable it in JBoss AS by editing /usr/share/jboss-as/standalone/configuration:
<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" native="false"> <connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http"/> <connector name="ajp" protocol="AJP/1.3" scheme="http" socket-binding="ajp"/>
You may find ‘scheme=”http”’ a bit odd here. This field is used to create redirect-URLs for the client, that’s why it’s ‘http’ and not ‘ajp’.
After restarting JBoss AS (as done earlier), AJP will be activated. You could verify this by issuing netstat -an | grep LISTEN, this should give you back an entry for tcp 8009.
To setup Apache httpd for reverse proxying, edit /etc/httpd/conf/httpd.conf and add a single line:
<Directory /> Options FollowSymLinks AllowOverride None </Directory> ProxyPass /jboss-as-hibernate4 ajp://localhost:8009/jboss-as-hibernate4
After restarting httpd:
sudo /etc/rc.d/init.d/httpd restart
you should be able to access the demo application on port 80 and path /jboss-as-hibernate4.
Note that if you want to change the context path as part of the proxying, configuration may become more complex. Generally, I would recommend avoiding that. In the common use case where you want users to type in the server name without any path and gain access to your application, I would recommend to do this with an index.html on the Apache httpd server that redirects the user to the context path. If you’re unhappy with the context path as derived by the WAR name, you may override that by including a ‘jboss-web.xml’ file in your archive next to the ‘web.xml’ file. In this file, you can set the context-root.
Installing PostgreSQL
Now, let’s get everything running on a ‘real’ database! We’ll install a PostgreSQL database. (Note that if you want to use the Amazon EC2 cloud for production, you might be interested in the Amazon RDS service rather than managing the database yourself.) Make sure you have pgAdmin running on your local machine.
Installing PostgreSQL is easy with yum:
sudo yum install postgresql9-server.x86_64
Now, we’ll have to set it up. The 2704-paged PostgreSQL manual may seem a bit daunting, but it’s actually not that hard. To just make sure the database is initialized and running, executing the following:
sudo service postgresql initdb sudo chkconfig --level 345 postgresql on sudo /etc/rc.d/init.d/postgresql start
Set a password for the postgres user and switch to it to do the rest of the PostgreSQL configuration:
sudo passwd postgres su – postgres
Now, we could gain access to the database with the ‘psql’ command, but we only need to create a user and a database for the datasource for our hibernate4 quickstart example, and this can be done from the shell:
createuser –D –P –R –S hib4qs createdb -O hib4qs hib4qs
PostgreSQL doesn’t allow any network communication by default for security purposes. We’ll have to enable it. Edit /var/lib/pgsql9/data/postgresql.conf and set the following:
listen_addresses = '*' port = 5432
Edit /var/lib/pgsql9/data/pg_hba.conf and add the following line above the other entries. If you add it below the other entries, access using pgAdmin will go fine but later on, the PostgreSQL JDBC driver won’t be able to connect properly.
host all hib4qs 0.0.0.0/0 md5
Now, you can exit the shell of the postgres user, and restart the database. After that, you should be able to connect to your database remotely (using pgAdmin) using the hib4qs user.
Connecting JBoss AS to PostgreSQL
First, download the JDBC4 driver and copy it to your instance. We’re going to setup PostgreSQL-support in JBoss AS as a ‘module’. First, create the module directories and copy the driver to it:
mkdir /usr/share/jboss-as/modules/org/postgresql mkdir /usr/share/jboss-as/modules/org/postgresql/main cp postgresql-9.1-902.jdbc4.jar /usr/share/jboss-as/modules/org/postgresql/main
Now, you should create in the same ‘main’ directory a file ‘module.xml’ with this content:
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="org.postgresql"> <resources> <resource-root path="postgresql-9.1-902.jdbc4.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
(I got this information from the JBoss forum.)
In /usr/share/jboss-as/standalone/configuration/standalone.xml, you should now add the PostgreSQL driver after the already present H2 driver:
<driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> <driver name="postgresql" module="org.postgresql"> <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class> </driver>
Restart JBoss to make these changes effective. To create the datasource, you may edit standalone.xml directly, but I prefer doing this through the JBoss management console. Create a new XA Datasource with the following:
Name | hib4qsDS |
JNDI Name | java:jboss/datasources/hib4qsDS |
Driver | postgresql |
XA property | Key: databaseName, value: hib4qs |
User | hib4qs |
Password | whatever you’ve chosen |
Domain | leave empty |
Enable the datasource, then test it using the button under the ‘connection’ tab.
Migrating the application to PostgreSQL
Now, we’ll make modify the hibernate4 quickstart example to use our PostgreSQL datasource. In the sourcetree, remove src\main\webapp\WEB-INF\ hibernate4-quickstart-ds.xml. Modify src\main\resources\META-INF\persistence.xml and replace the datasource ‘Hibernate4QuickstartDS’ with ‘hib4qsDS’. Run a ‘mvn clean package’, and deploy the application. You should now be able to use the application, and with pgAdmin you should be able to see the created database schema and content.
This completes our setup. As a last step, you might want to check the reboot behaviour. After a sudo shutdown –r now, the application should come up again without manual intervention, in 3 minutes or so.