text:
Category Archives: FW/1
Improved connector for Nginx proxy to Railo
Edit: This post is outdated. Please see this post https://kisdigital.wordpress.com/2013/03/04/my-final-nginxrailo-connector/
I have been working with Nginx quite a bit in the last week and I have had a little time to fine-tune my configuration a bit. Here is my stock Railo configuration. I have saved the settings to their own file and include the connector in each separate server configuration that requires Railo. This also remaps the standard Railo administrator to a more secure location and optionally sets basic authentication.
# /etc/nginx/railo_connector.conf # Block default Railo admin if ($request_uri ~* ^/railo-context){ return 404; } # Hide the Railo Administrator and optionally lock down with password location ~ ^/hardtoguesslocation/(.*)$ { #auth_basic $host; #auth_basic_user_file /path/to/htpasswd; if($request_uri ~^/railo-context/admin){ return 404; } location ~^/hardtoguesslocation/{ rewrite ^/hardtoguesslocation/(.*)$ /railo-context/admin/$1 last; } } # Main Railo proxy handler location ~ \.(cfm|cfml|cfc|jsp|cfr)(.*)$ { proxy_pass http://127.0.0.1:8888; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; }
Also, Nginx allows you to use variables in your server configuration so it allows you to easily create a "catch all" virtual host. You can quickly add a new website just by adding it to your server.xml in Railo with no additional configuration required unless you require domain specific rewrites etc. Here is an example server configuration with a default virtual host and a separate domain configured:
server { #Catchall vhost listen 80; ## listen for ipv4 server_name _; root /var/www/$host; index index.cfm; access_log /var/logs/nginx/$host-access.log; # Do not log missing favicon.ico errors location = /favicon.ico { access_log off; log_not_found off; } # Do not serve any .hidden files location ~ /\. { access_log off; log_not_found off; deny all; } include /etc/nginx/railo_connector.conf; # End of catch-all Server Configuration } server { #A domain with custom handling listen 80; ## listen for ipv4 server_name mydomain.com www.mydomain.com; root /var/www/mydomain.com; index index.cfm; access_log /var/logs/nginx/mydomain.com-access.log; # Do not log missing favicon.ico errors location = /favicon.ico { access_log off; log_not_found off; } # Do not serve any .hidden files location ~ /\. { access_log off; log_not_found off; deny all; } # Handle FW/1 style SES urls (i.e. http:/domain.com/main/default/key/value) location /{ try_files $uri $uri/ @ses; } location @ses{ rewrite ^/index.cfm/$uri last; } include /etc/nginx/railo_connector.conf; # End of custom Server Configuration }
If you want the X-Real-IP reported correctly on the Railo server you will also need to add the RemoteIP valve to your Tomcat configuration.
Overall Nginx makes a very nice front-end to Railo and as always I welcome any comments or suggestions to make it better.
Demo site
I have a new site up to house some of the demos I have done. You can now see the chat application in action instead of a screenshot. I also make use of Jason Delmore's ColdFISH project for code viewing. It is still a work in progress, but it is up and running if you want to check it out.
This is also the first site I have done using Sean Corfield's Framework One. Things should be pretty stable now, but if you notice any issues I blame it on learning curve. 😉
Edit: Demo site is temporarily down.
Day two with FW/1
Playing around with FW/1 today I decided to take a look at the differences at how services differ from working with domain objects. Skimming through the FW/1 documentation I did notice the framework has a built in function to populate a bean, namely the fw.populate() function. Calling a bean (an object with getter/setter methods) is not much more involved in calling a service. First, you create an instance of your bean. Then call populate() method passing rc keys that you would like to set and the populate function will find the setX method in the bean and set the appropriate value.
I have an extremely simple application I have setup that has two views. The default view is just a form that gets posted to the main.submit action which is just cfdumping the rc scope.
The sample "bean" setup for testing purposes:
<cfcomponent> <cffunction name="init"> <cfscript> variables.instance = structNew(); instance['fw'] = arguments.fw; </cfscript> </cffunction> <cffunction name="setFirstname"> <cfscript> instance['firstName'] = arguments.firstName; </cfscript> </cffunction> <cffunction name="setLastname"> <cfscript> instance['lastName'] = arguments.lastName; </cfscript> </cffunction> <cffunction name="saveUser" returntype="struct"> <cfscript> var response = structNew(); response['message'] = "Saving user: " & instance.firstName & " " & instance.lastName; </cfscript> <cfreturn response/> </cffunction> </cfcomponent>
Nothing too complicated going on here, just a basic init method to setup the instance variables, two setter methods and finally a method for "saving" our user information. The controller method for handing the submit is as follows:
<cffunction name="submit"> <cfargument name="rc" type="struct"/> <cfscript> var userObj = createObject("component", "model.user"); variables.fw.populate(userObj, "firstName,lastName"); structAppend(rc, userObj.saveUser()); </cfscript> </cffunction>
This creates the user object, populates the values and then saves the user and appending the results into the rc scope. Services are a little easier to implement as they have a one line invocation. I am still trying to figure out when it would be best to use a service to move data in and out of the application as opposed to creating a bean in the model. I would imagine the ultimate answer would be whatever works best for you, but I can see where services could be advantageous as well. I welcome any comments.
Day one with FW/1
Aside from fun jQuery projects, I have really been meaning to pickup Framework One and really check it out. After using XML controllers for a while not having to worry about defining all the behaviors is nice. Best of all, it is really intuitive to work with. After installing the FW/1 package I immediately deleted all the example applications and the introduction folder, that is just how I roll.
Then I started with a minimum framework: a default layout, a default view and a default controller. I had everything up and running quickly. Next I decided to write a sample application. Nothing too fancy, enter a first and last name in a form and a submit button. I could have went with the typical "Hello World" application, but I am kinda finicky about form processing. The framework I use does not automatically append the form scope into the request context. Generally I default all my form values for my view in the controller and then roll the form scope in, overwriting my defaults with any values that might be in the form scope. If validation fails, I can always fall back to my submission page and have form values defaulted. It did take me a little while to adjust to FW/1's way of doing things, but it was not a large adjustment.
I also like how FW/1 allows for a startItem, endItem for controller methods. It allows you to easily handle validation before the main method gets called. I suppose the validation could be handled in the main method but I find it a little clearer when I break the logic into distinct pieces.
Finally I setup a simple "user" service. In this case, it was just to return a string letting me know the user's first and last name that was entered on the form. The whole thing came together in less than an hour from start to finish, including time spent looking over the documentation when I did not fully understand something.
Although there are several aspects of the framework that will require me to change the way I handle certain things, I can see the framework is flexible and extremely easy to use. I will definitely be using FW/1 in some future projects.