How to override the new plain white background in Twitter

As many of you know, Twitter just removed the ability to customize backgrounds on the web client. It’s bad-ish that they removed the ability to add custom graphics as a back ground, but far worse, they removed the ability to change the background colour, leaving users with an eye-bleeding, headache inducing bluish white. new-9

Well, “the Man” might be wanting us to just shut up and deal with it but we don’t have to take it. StyleBot allows us to edit the CSS (stylesheet) of any page. It is originally intended as an accessibility tool as it allows users to change colours (to make them high contrast), font sizes  etc, however we can use is to stick it to the Twitter man, The great thing about this is that we can save the styles and the plugin changes the colours pretty much permanently.

The following works for Chrome and there’s probably similar things you can do in Firefox & maybe IE.

Install the free StyleBot from the Chrome Store

You will now have a CSS button in the upper right. Right click on it and select Options.

new-2

Select the Styles tab

new-7

Click Add a New Style

Then add the URL twitter.com and the 3 lines of CSS code. (Important: everything is Case Sensitive)

body {
    background-color: #4a7383;
}

I like a dark-ish blue but you can pick what ever value you want. There’s a good colour picker tool here at Mozilla

new-6

Now click the save buttton, reload your Twitter tab and say ahhhh.

new-11

You’ve got a background that you control. And there’s nothing the Man can do about it. You can go crazy and change fonts, layouts and a lot more or use one of the pre-built style for Twitter & many other sites from StyleBot Social but for me, I just wanted the background colour changed.

Note: this only affects what -you- see. If you wanted to customize your Twitter page for others, you’re out of luck. At least until Twitter starts charging you to customize it. Which is my guess as to why they have done this miserable thing in the first place.

Update: Noticed that Twitter cards are changed by this as well.

new-12

I don’t like that but it’s easy to change. All we need is to do is add an entry for Twitter Cards.

body {
   background-color: #4a7383;
}
div.TwitterCardsGrid {
    background-color: #ffffff;
}

Another little tweak.

if you use analytics.twitter.com and don’t want that page altered (it’s quite hard to read with a dark background.)

Add an entry with just a white (#ffffff) background.

Capture

Then modify the original URL to ^https://twitter.com/

Capture

This applies the fix to the main twitter page but not to analytics.

Update #3

Firefox users can install Stylish

Load Twitter.com

Click the S icon and then Write new style > for twitter.com

new-14

new-15

Place your cursor between the { } on line 4 and paste the CSS code from above. Give it a name and click save.

new-16

Advertisements

Coldfusion Directory Monitoring with Event Gateways

This just came up on Twitter today and I realized I hadn’t posted about it so here you are.

Many hacks of ColdFusion over the years have been through people manipulating the CFIDE directory. (the most famous being the FCKeditor Hack) There are many ways to combat this but here’s a simple one.

Using the DirectoryWatcher Event Gateway built into CF versions 8 & up, you can in just a few minutes set up some code to monitor & alert you of changes to the CFIDE (or any other) directory.

You need 2 piece of code.

The Config File

CFIDE_Alert.cfg

# The directory you want to watch. If you are entering a Windows path
# either use forward slashes (C:/mydir) or escape the back slashes (C:\\mydir). 
directory=C:/Inetpub/wwwroot/cfide
# Should we watch the directory and all subdirectories too
# Default is no. Set to 'yes' to do the recursion. 
recurse=yes
# The interval between checks, in milliseconds
# Default is 10 seconds
interval=10000
# The comma separated list of extensions to match.
# Default is * - all files
extensions=*
# CFC Function for file Change events
# Default is onChange, set to nothing if you don't want to see these events
changeFunction=onChange
# CFC Function for file Add events
# Default is onAdd, set to nothing if you don't want to see these events
addFunction=onAdd
# CFC Function for file Delete events
# Default is onDelete, set to nothing if you don't want to see these events
#deleteFunction=

and a CFC to use for the Gateway. (note: I don’t have Delete events turned on as I delete CFIDE/Admin files when not in use…for another post)

CFIDE_Alert.cfc

<cfcomponent>
<cffunction name="onAdd" returntype="any">
<cfargument name="CFEvent" type="struct" required="yes">
<cfset data = CFEvent.data>


 <cfmail to="webmaster@example.com" 
		server="yoursmtp.server"
		username="youruname"
		password="yourpwd"
		from="alert@example.com"
		subject="CFIDE CHANGE DETECTED!"
		type="html">
<cfdump var="#data#">
</cfmail>
</cffunction>

<cffunction name="onCHANGE" returntype="any">
<cfargument name="CFEvent" type="struct" required="yes">
<cfset data = CFEvent.data>


 <cfmail to="webmaster@example.com" 
		server="yoursmtp.server"
		username="youruname"
		password="yourpwd"
		from="alert@example.com"
		subject="CFIDE CHANGE DETECTED!"
		type="html">
			
<cfdump var="#data#">
</cfmail>
</cffunction>

</cfcomponent>

Then all you need to do is create the Event Gateway

Capture

Now, if any files are changed or there are files added, you are sent an email. You could also use Event Gateways to send a an SMS message so you can be notified anywhere, anytime.

Capture

The Mysterious Spy.log – Coldfusion & JDBCSpy

A couple of week ago, I found a file on my internal web server called spy.log, which gave me a bit of a scare (but then I realized nobody spying on me is likely to call a file spy.log) This file was almost 20G in size. What’s up with that? After finding a viewer to open a 20G text file, I determined that this was a legitimate file belonging to JDBCSpy, which is an extension of the Coldfusion JDBC driver which can optionally be enabled. To enable it, you just have to add a reference to the Coldfusion Datasource Connection String in the Advanced section.

SpyAttributes=(log=(file)C:\\temp\\spy.log;logTName=yes;timestamp=yes)

Thing is I don’t remember enabling it.  I found some more information on Charlie Areharts’ blog which reminded me that at one point I had installed a demo version of Fusion Reactor to diagnose some performance issues. I’m not sure if the version of FR I installed modified the connection string and did not remove it when I uninstalled the program, or if I added it (note to self: make better changelog notes please).

In any case, the fix was simple, delete the connection string attribute and restart the CF services.

 

 

 

A Simple Way to Clean Up Your InBox

I don’t know about you, but I manage 3 different email accounts at work. These accounts have been around for a very long time (+10 years) and over this time they’ve have showed up on many, many email marketing lists. One account was getting 30-50 emails per day from marketers, auto-added newsletters and other sundry sources. Every day I would dutifully open up my email client, then play the delete game. Then one morning last month I had a revelation. I don’t read any of this stuff. Most of these emails are coming from legitimate sources. Many use SafeUnsubscribe or similar services.

UNSUBSCRIBE!

Wow. What a concept. Why did it take me so long to figure this out? A couple of reasons I guess. Habit & Creep. Back in the bad old days clicking on an unsubscribe link often was simply a way for spammers to verify an address so I got in the habit of simply trashing everything. (And I don’t make a habit of clicking on links in emails – we all know that’s a really bad idea right???) Since most of the emails I was getting were from obviously legitimate sources using services like Constant Contact (who provide the SafeUnsub system), I could be assured that I could with a careful click (hovering over the link, verifying that it was pointing to a site I expected, etc) I could rid myself of these emails. Aside from habit, creep is the other reason. A newsletter here, a weekly sales blast there and suddenly you’ve got 50 marketing emails a day.

So there you go. Make a resolution for 2012 to clean up your inbox. It’s dead easy. And my InBox – down to 4 marketing emails today (unSUBBED!) and 6 from friendly suppliers in China – which I guess I’m stuck with.

Project Honeypot & Coldfusion Part 2

One of my more popular posts has been Stopping Comment Spammers & Email Harvesters with Coldfusion & Project Honeypot. This code has been working very well for me and I have seen a noticeable decrease in comment spam. It also seems to be working for Project Honeypot, at least in a small way.

My Stats

  • Harvester visits to your site(s): 42
  • Recent visits (this week): 3
  • Recent visits (this month): 9
  • Spam traps issued on your sites: 304
  • Spam received at your addresses: 1,089
  • Received this week: 112
  • Received this month: 417
  • Comment spam posts to your site(s): 0

A code update.

One of the things I noticed since implementing the code in my previous post, my site page load times were up quite a bit. The reason is that the code uses http:Bl to do a DNS look up to the project servers for every page load. This takes -time-. I decided to add my own white list table and some code to eliminate these multiple look-ups.

The table is simple, just

visitor_ip_addys [varchar(15)]
visitdate [datetime]

I added the following function to my Honeypot CFC

<cffunction name="newVisitorCheck" returntype="string">
   <cfargument name="ip" required="yes" type="string">
   <cfset var vQry = "">

  <cfquery name="vQry" datasource="myDSN">
    select ipaddy from visitor_ip_addys where ipaddy = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.ip#">
  </cfquery>

 <cfif vQry.recordcount eq 0><!--- then it's a new visitor  --->
   <cfset result = "new">
 <cfelse>
   <cfset result ="existing">
 </cfif>
<cfreturn result>
</cffunction>

And changed my honeyPotCheck function to

<cffunction name="honeypotcheck" returntype="struct" hint="Check Project HoneyPot http:BL">
  <cfargument name="ip" required="yes" type="string">
  <cfset var aVal = "">
  <cfset var hpkey = "MyKey">
  <cfset var stRet = structNew()>

<!---jb: added check to see if this ip has visited in the last 3 months. We have a table to track ips which is retained for 3 months. IP's that check as clean
against http:BL are added to this table to increase page load performance. The table is cleared every 3 months to revalidate visitors (in case they may have been
compromised in that time and to keep table size reasonable --->

<cfinvoke method="newVisitorCheck" returnvariable="result">
<cfinvokeargument name="ip" value="#arguments.ip#">
</cfinvoke>

<cfif result eq "new">
  <!--- Get the different IP values --->
  <cfset aVal = listToArray(gethostaddress("#hpkey#.#reverseip(arguments.ip)#.dnsbl.httpbl.org"),".")>

        <cfif aVal[1] eq "IP-Address not known"><!--- jb: added evaluation of array for good addresses --->
        <!--- set a value indicating ok address --->
            <cfset stRet = {type=99}>
            <!--- insert into visitor_ip_addys table as this is a clean IP --->

            <cfquery name="iQry" datasource="MyDSN">
            insert into visitor_ip_addys (ipaddy, visitdate) values
            (<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.ip#">,
            <cfqueryparam cfsqltype="cf_sql_timestamp" value="#now()#"> )
            </cfquery>

        <cfelse>
          <!--- there was a match so set the return values --->
          <cfset stRet.days = aVal[2]>
          <cfset stRet.threat = aVal[3]>
          <cfset stRet.type = aVal[4]>

          <!--- Get the HP info message ie: threat level --->
          <cfswitch expression="#aVal[4]#">
           <cfcase value="0">
            <cfset stRet.message = "Search Engine (0)">
           </cfcase>
           <cfcase value="1">
            <cfset stRet.message = "Suspicious (1)">
           </cfcase>
           <cfcase value="2">
            <cfset stRet.message = "Harvester (2)">
           </cfcase>
           <cfcase value="3">
            <cfset stRet.message = "Suspicious & Harvester (1+2)">
           </cfcase>
           <cfcase value="4">
            <cfset stRet.message = "Comment Spammer (4)">
           </cfcase>
           <cfcase value="5">
            <cfset stRet.message = "Suspicious & Comment Spammer (1+4)">
           </cfcase>
           <cfcase value="6">
            <cfset stRet.message = "Harvester & Comment Spammer (2+4)">
           </cfcase>
           <cfcase value="7">
            <cfset stRet.message = "Suspicious & Harvester & Comment Spammer (1+2+4)">
           </cfcase>
          <!---  <cfdefaultcase> jb: moved to top of function as we can't eval the array if there is no lookup response ie: not match in http:BL
            <cfset stRet.message = "IP-Address not known">
           </cfdefaultcase> --->
          </cfswitch>

        </cfif>
  <cfelse>
    <!--- good address  --->
    <cfset stRet = {type=99}>
</cfif>
  <cfreturn stRet>
 </cffunction>

As you can see from the comments in the code, I do the look-up (newVisitorCheck) when honeypotcheck is invoked, which is on each page load. The check does a query to see if that IP is in our white list table. If it is, then we skip the rest of the check and do not do a http:Bl DNS query. If it does not exist in our white list, that either means that the IP is new so we need to check it, or that it is a known bad IP. This means that new visitors have a slightly longer wait on first page load as we are doing the look-up, but then if they pass the look-up, we add them to the white list* and do not slow them down for subsequent page loads. As noted in the comments, we keep entries in the white list for 3 months (an arbitrary number).

After 3 months, we remove the IP from the white list so we can recheck it to make sure the IP hasn’t been compromised.

The code to do this is:

<cffunction name="ipTableCleanup" access="Remote">
<cfquery name="deleteIP" datasource="myDSN">
    delete from visitor_ip_addys where visitdate <= DATE_ADD(CURRENT_TIMESTAMP, INTERVAL -90 day)
</cfquery>
</cffunction>

This is run every day via a schedule task set up in CFAdmin.

All in all, this seems to be working quite well as page load times are back to where they were before the Honeypot implementation and the Honeypot is still doing its job.

*Note that since you are capturing & storing IP addresses, your privacy policy should reflect this fact.

QR Code Generator Update

I’ve just found a bug in the way I wrote the original code for my QR Code Generator

Update 2: Thanks to a comment from Michael, I’ve found another way to fix the issue by adding encodeURIComponent to the JS function. See the comments for details. Now you have 2 ways to do it 🙂

The problem is that by using the url scope you can only get one url parameter to pass to the Chart API from the variable #url.siteurl#.

If you enter

http://www.testserv.com?foo=1&bar=2

as the input value of the text box, the value of url.siteurl becomes http://www.testserv.com?foo=1 and then CF creates -another- URL variable called bar with a value of 2.

This had me stumped for a while. but what is happening is that the url being passed as

dsp_qrcodeGen.cfm?siteurl=http://www.testserv.com?foo=string1&bar=string2

What we get when we do a <cfdump var=”#url#”> is

param1 (siteurl) = http://www.testserv.com?foo=string1

param2 (bar) = string2

See what happened there? Everything after the first ? (dsp_qrcodeGen.cfm?) up to the first & (&bar) becomes a param pair and then everything after the & becomes a pair. Problem is we don’t -want- to pass 2 url params. as we’d have to handle them by doing something like

<cfhttp url="http://chart.apis.google.com/chart?chs=200x200&cht=qr&chl=#url.siteurl#&someparamname=#url.someparamname#" result="qrcode" getasbinary="yes">

This gives us the proper string to pass but it requires us to hand code the cfhttp call making it very inflexible.  It becomes even more difficult as we need to pass additional params. You could probably code up a parsing loop of some kind but there is a much simpler method.

CF does not  parse form variables in the same way it does URL params, so by using the form scope, CF doesn’t break apart the string that we feed it.

<cfoutput>
<div style="margin:auto; width: 700px; height:450px;padding:25px;text-align:center;border:1px solid;">
    <form method="post" action="dsp_qrcodegen.cfm">
        <h3>QR Code Generator</h3>
        <hr>
        Input URL
        <input type="text" name="siteurl" id="siteurl" style="width:500px;margin:50px 0 50px 0;"><br>
        <input type="submit">
    </form>
    <cfif structkeyexists(form, "siteurl")>
        <div style="margin:auto;">
        <cfhttp url="http://chart.apis.google.com/chart?chs=200x200&cht=qr&chl=#urlencodedformat(form.siteurl)#&chld=H|0" result="qrcode" getasbinary="yes">
        <cfimage action="writeToBrowser"  
                 source="#qrcode.filecontent#" />
            <br>
            #form.siteurl#
        </div>
    </cfif>
</div>
</cfoutput>

#form.siteurl# stays siteurl=http://www.testserv.com?foo=string1&bar=string2 so all our params get passed and you can add as many additional params as you like.

Installing Railo/Tomcat on 64 bit Windows Server 2008 R2 with IIS 7.5 and Plesk – The Correct Way

November 2015 UPDATE: Obviously this is an old post but it still gets hits. Everyone should know that Railo is a dead project. The main developer has forked it into Lucee (found on lucee.org). Lucee is currently stable at v4.5x with public beta testing of v5. Lucee is by far the best non Adobe CF interpreter and I highly recommend it.

This is an update of the post on setting up my new server and my struggle to get Railo installed. After a few tips from Google Groups for Railo and specifically Mark Drew (CEO Railo UK & original author of cfeclipse, my favourite CFML editor) & Jordan Michaels (Community Deployments Coordinator – ie: the install guy), I decided to reprovision (ie: reinstall) my virtual server and give it another try. I actually did this final setup twice, once to get it to work and once to document it. I’m getting pretty good at it now 🙂

Basically, the problems I experienced in the first few times around were due to 2 things; Plesk and my confusion (or IIS 7.5 lack of clarity) as to what Enable 32 Bit Applications means. Plesk does quite a few funky things to IIS since it is a web based management tool. Much of my grief stemmed from the fact that Plesk is a 32 bit App and my server install is 64 bit. Plesk also uses but doesn’t expose a version of Tomcat. My confusion in the original post as to why the Railo Tomcat was installing itself on a different port than normal was likely due to the Plesk instance. Now we don’t want to break Plesk (I’m paying for it every month!) so we need a procedure to make it play nice and undo some of the problems it causes with IIS. The following outlines the steps needed to get Plesk, Railo, Tomcat & iis 7.5 all running happily.

The first section of my previous post outlines how to set up the server and a single website using Plesk on a GoDaddy VPS (virtual private server). I’m assuming Plesk operates pretty much the same on all II 7.5 setups so it should be pretty standard. That setup walkthrough is still valid however, as I found out, the remaining part of the post dealing with Railo & IIS is incorrect (well, not exactly incorrect – it did get things working, just not in the best way) and superseded by this. I’ve also changed the order in which I did some things so let’s get started.

Fixing what Plesk Hath Wrought

Once we’ve created our website via the Plesk panel we need to go and make some changes in IIS so fire up inetmgr

Select Application Pools under the main node of your site. You’ll notice there a couple of the standard and a couple added by Plesk.

Click Set Application Pool Defaults from the right column. Here we see that Plesk has set Enable 32 Bit Applications to True. We need to set this to false.

This was a big stumbling block for me on the first couple tries as I did not have a clear understanding as to what Enable means. For IIS 7.5 Enable means Only Allow.  So If you have this set in defaults it will create all new AppPools with 32 bit enabled preventing 64 bit apps from running. You will get an error: HTTP Error 500.0 – Internal Server Error Calling LoadLibraryEx on ISAPI filter “C:\railo\connector\isapi_redirect-1.2.31.dll” failed.

The other very confusing thing is that this seems to override individually set AppPool settings and break all 64 bit websites if 32 bit is enabled in Application Pool Defaults.  In order to have a mixed 32/64 bit environment you MUST have Application Pool Enabled 32 bit Application set to FALSE. To allow an individual site to run 32 bit apps, you need to click on the appPool you want to change and click Advanced Settings from the right column.Change the drop down from False (the default) to True

For Plesk to work we need to set  both plesk(default)(2.0)(pool) and PleskControlPanel to use 32 bit applications. Once you have done this, browse to your Plesk panel and verify everything is working.

Now that we’ve got Plesk in a 64 bit environment, we need to add an AppPool for our new website. Click Add Application Pool in the right column and give your pool a meaningful  name. The name of the website works well. Leave the other settings as they are.

Now that we’ve got that set up, we need to associate the new AppPool with the new website. Select the website in the left column and then click Advanced Settings from the right. You’ll note that the website is set up by Plesk to use plesk(default)(2.0)(pool). Click on this and then  click on the […] Select your new AppPool and click OK.

Install Railo

Not much to say here. Run the setup routine, making note of your Tomcat admin password. The installer may request that you choose a port for Tomcat. If you don’t get asked, it means that Tomcat can use the default port. If you do, it means that something is using that port. I assume it’s Plesk’s version of Tomcat? This happened twice and the rest of the time it didn’t on the various installs I’ve tried. Does Plesk choose different ports at setup? I don’t know. Remember, my install is based on an OS image with Plesk pre-installed so I don’t have any control over it’s install.

Once the install is complete and you get the first run page, set your Server & Web Admin Passwords for Railo.

Now we need to fix one more issue introduced by Plesk. This one was another stumbling block in my initial tries. Because I installed Railo immediately, I did not know that Plesk had already set up a jakarta virtual directory pointing to its own version (32 bit) isapi connector for use by its own version of Tomcat. Without going into too much detail about that, the jakarta vDir in any application that uses railo needs to be pointed at the railo isapi 64bit  connector (on a 64 bit OS). Click on the jakarta subdirectory of your website, Click Advanced Settings in the left column and  point the physical path of the Railo connector

Now we’ve cleared up all the issues caused by Plesk and it’s time to move on to the final set up of IIS 7.5

The Home Stretch

The Railo install does a lot of the work for you but we do have to do a few things. The server root node will have a Handler Mapping for *.cfm files set up, but it doesn’t seem to set it up for individual sites. Click on your website node and then Handler Mappings. Click Add Script Map from the right column. Set the Request Path to *.cf*. All the Railo walkthroughs I’ve seen only seem to add one for *.cfm. The installer only adds *.cfm but I’m not sure if it will process CFC’s if only *.cfm is set up. I assume it will but it won’t hurt to use *.cf* to cover both right?

edit: While I don’t think it will do any harm to set it to *.cf*, setting/leaving the Handler Mapping as *.cfm is fine. Now that I have an actual operating system, I was able to verify that CFCs were processed correctly with only a mapping for *.cfm

Point the executable to the {installPath}\connector\isapi_redirect-xx.xx.xx.dll and give it a name.

*note: some of the more eagle eyed of you may notice that the path in the handler mapping screen cap above shows I’m adding the Handler Mapping in the {website} > jakarta section. This was not intentional. You should be in the root node of your website when you add an handler mapping. In this case it should have been railoinstalltest.ca


Now double check that there is an entry for the isapi connector in the Isapi Filters section. This should be added by the installer but if not you can add it easily.

One final thing to do is to make sure that index.cfm is at the top of the Default Documents list (not necessary but I’d do it in any case). Index.cfm should be added by the installer, but if not you can add it.

Adding a Tomcat Webcontext

Click on Start Menu >All Programs  > Railo >Tomcat Host Config to open up the Tomcat Server.xml file (a nice touch added by the installer). Scroll to the bottom of this file to add your “webcontext”; basically tell Tomcat what directory to watch under what website. There is a template to use which is commented out with <!– –>

<!–
<Host name=”[ENTER DOMAIN NAME]” appBase=”webapps”>
<Context path=”” docBase=”[ENTER SYSTEM PATH]” />
</Host>
–>

Copy that twice and modify it to add the Hostnames of your site and the path to the document root.

<Host name=”railoinstalltest.ca” appBase=”webapps”>
<Context path=”” docBase=”C:\inetpub\vhosts\railoinstalltest.ca\httpdocs” />
</Host>

Note that there are two instances for a single site; one for http://www.railoinstalltest.ca and one for railoinstalltest.ca. You would need to repeat this for each binding your site has that you want to process cfm files. You wouldn’t need to add one for http://ftp.railoinstalltest.ca but you probably would for admin.railoinstalltest.ca

edit: Thanks to Spills in the comments for pointing me to the use of Alias. Add an alias for each binding of your site that you want to process cfm files. Saves a few lines and if you have a lot of sites, it keeps the file cleaner.

<Host name=”www.railoinstalltest.ca” appBase=”webapps”>
<Context path=”” docBase=”C:\inetpub\vhosts\railoinstalltes.ca\httpdocs” />
<Alias>railoinstalltest.ca</Alias>
</Host>

Save the file and restart Tomcat using Start Menu >All Programs  > Railo > Railo-Tomcat Service Control

Now at this point we -should- be able to browse our first cfm file. (but I bet you’re guessing maybe, just maybe we can’t?)

Create a simple one
<cfoutput> <h1>Hello World!</h1><br> The time is #now()#</cfoutput>

and save it to the httpdocs folder of your website and browse to the site and…

You’ll note the error detail Cannot read configuration file due to insufficient permissions. Now we know that the website configuration file is web.config and it is located in the document root of each website. So the error message tells us that for some reason, IIS doesn’t have permission to read that file, or more accurately, the website’s AppPool doesn’t. In IIS 7.5 the appPool is an isolated security context for each website, provided you set them up that way as we did. We need to give the appPool permissions to access the directory. Open Explorer and browse to your webroot, in this case inetpub\vhosts and select your website. Right click and select the security tab. Click Edit and then Add. In the Object Names box enter IIS AppPool\{nameof yourAppPool} or in this case IIS AppPool\railotest. Click ok.

Now at this point (again) you’d think we’d be done, but I discovered that granting permissions at the topmost level of the site doesn’t propagate the changes to lower directories like you’d expect. I’m not sure if this is a Server 2008R2 thing or something related to IIS AppPool objects but we need to do one more thing. From the Security Tab of the properties box, click Advanced > Change Permissions. Click in the Permission Entries box and select all of the entries, including the AppPool entry you just added. This step is important and failure to do so can mess up the permissions for the site. Click the Replace All Child Object Permissions With Inheritable Permissions From this Object check box. This will set the permissions of all of the subdirectories of the root website based on the permissions of the root directory (ie: the one we just added the AppPool permission). It does this for each Permission Entry in the list. As such all of the subdirectories will have permissions Read & Execute, List Folder Contents and Read set for your website AppPool.

Finally, back to the browser and …..

Ahhh, I love it when a plan (and 2 weeks, 5 OS reinstalls and several hundred cups of coffee) come together.

Unlike my previous post, I’m pretty confident that this is the correct way to get these various pieces of code to live on my webserver in glorious harmony. I didn’t realize when I started this project that I would be spending this much time just getting the server set up, but in retrospect, I’m glad it did. I have a much better understanding of how all the various pieces work and feel much better about the way my server is set up. My initial attempts led to so much random clicking of settings that I could have easily compromised the security of the server. I’m very glad that I have a VPS so flattening the server and starting again was a simple, 2-3 hours automated process which required none of my time.

As before, If you’ve got any corrections or suggestions, let me know about them in the comments.