SSHFS: A Perfect Remote File Manager?

SSHFS is a Fuse-based Linux filesystem that allows you to connect to an SSH server, and mount it as you would any other mountable device.  The difference is… this “device” is a remote server using an SSH connection.  At Holley Grove, we use SSHFS on all of our servers, SSHFS might be something you should consider as well… here’s just a few reasons why:

  1. You’re basically using SSH to communicate.  SSH is encrypted, and as such can be one of the most secure methods of communication available.
  2. The setup is relatively simple, as you only need a few libraries on the client computers, and an SSH server running on the remote server.
  3. Permissions, users, and groups are all preserved as they would be using normal SSH.
  4. You can turn off in-secure, un-encrypted FTP completely.
  5. Fast access to files via your file manager application as if they were stored locally on your computer.  For Linux Gnome users, your SSHFS mounted shares will show up in Nautilus and act accordingly.

HowTo:

For Ubuntu, simply install sshfs via the package manager.  You’ll then need to add your Ubuntu user account to the Fuse group so that you’ll have permission to use Fuse.  To do this, go to System -> Administration -> Users and Groups.  Click on your username and click the “Properties” button.  Make sure the checkbox for “fuse” is checked and save your settings.  You may need to log out and log back in for these changes to take effect.  Now you can mount an SSH server in the directory called “remote”:

sshfs landon@holleygrove.com: remote

And to disconnect:

fusermount -u remote

SSHFS Desktop ExampleIt’s great to be able to run a command to mount an SSH server, then pop open nautlius and have all the remote files and directories listed right there just as any other files!

Sweet Relief

Starbucks Coffee CupI am not a smoker, but I can identify with those who are…  I would imagine lighting up your first cigarette of the day would be a lot like having your first triple ventii soy chai latte (or whatever the case may be).  It’s a bad habit, yes, but for many it is almost impossible to break.

Yesterday I was stuck in Hartsfield Hell for about 6 hours while I waited for the snow to “let up.”  I can indeed bear witness to the fact that the very first sip of this magical beverage somehow instantly made me feel better.  When you think about it, it’s kind of scary that a company’s product has such an addictive influence on so many of it’s consumers.  In fact, a Google search on “Starbucks Addiction” turned up a whopping 6,490 results.  There are even howto articles written by actual M.D.s on how to break your Starbucks addiction.  Over-exaggerated product enjoyment, or mass consumer addiction?

Simple Candidate Aptitude Test

When looking for new hires, many companies make the mistake of requiring all candidates to complete a simple skill test.  At first, these tests seem like a good idea, and a quick way to eliminate a huge chunk of possible applicants who aren’t as technically proficient as you need them to be.  However, often times, these “simple” tests offer no real benefit to the employer, waste time for both the employer (and it’s developers who have to sift through the results) and the applicant, and can actually have detrimental results on your hiring campaign.

Reason #1: Insulting the Wrong Crowd

Let’s suppose that you’re looking to hire a few mid to senior level developers for an object-oriented PHP position.  So, you may spend the course of a week developing some really great, practical PHP questions and problems.  After you’ve posted the job on dice, you’ve got a few offers, yay!  Kindly, you’ll send them an email with your “simple” questionnaire attached and give them a 24-hour deadline to complete the problems.  Well, right off the bat, you’ve turned off a number of qualified candidates by requiring them to take time out of their day to submit a blind PHP test that is admittedly “simple”.  Many of the most qualified and highly sought-after candidates may view your test as beneath them, too basic, boring, and a waste of time.  Some of the most qualified candidates may have years and years of experience (some may have even more than you!); they may have built some extremely successful and robust projects far beyond the range of what you are even hiring them for; they may have advanced degrees, have started their own companies, done consultant work for even larger companies; they may also be recognized leaders in the industry… Those are precisely the kind of applicants your company needs, but also precisely the kind of applicants that feel an aptitude test (with basic aptitude questions) is well beneath their skill level.  “Any position that may require completing such a simple test, is probably a low-level code-monkey style position anyway.”

Reason #2: Logistics

Let’s take a second to think about the types of people are most likely to excel at a “take home” aptitude test.  Chances are you’ve run into these same people before…  These people are great test takers, and they excel at scouring the web and regurgitating information verbatim.  They will put in long hours, and they can afford to work all night on this test, mostly because they don’t have as many other applications to fill out as the more qualified candidates.  They spend hours finding the exact right answers (which they did NOT already know and probably didn’t even take the time to comprehend).  They’ll polish up their answers, add some extra bells and whistles to their code (such as CSS styles and simple Javascript), and submit their results to you just before the deadline.  On the surface their results look great, but they are not there to explain their answers, describe to you their thought process, or even tell you how they arrived at their conclusion.  So, all you’re really left with is some simple, regurgitated information from the web looked up by the same person who’s cheated his or her way through the majority of his or her academic and professional life… probably not your ideal candidate.

Reason #3: Missing the Point

In the tech industry, code tools, languages, and platforms are often times stressed as the most important aspects of an applicant’s resume.  This couldn’t be a bigger misconception.  The truth is, an applicant’s ability to think, design, problem-solve, and engineer overall solutions will determine his or her success in any technology-laden position, not his or her experience with a particular language.  Everyone knows a guy who has 20+ years experience with C programming, but has no concept of how to design a scalable, robust, object-oriented application.  His experience far out-matches that of a newly graduated Doctoral student, but when placed with the responsibility of designing a system from scratch, he has no idea which route would be best to take in order to solve the problem, he just immediately starts hacking his C libraries.  With an aptitude test, you may very well validate the applicants who’ve memorized all the built in functionality of their particular language, but you really haven’t evaluated their ability to problem solve efficiently, which, is really what development is all about.

MySQL Blob Insert Error

When using MySQL to store things such as files, it is best to use a blob field.  If you’re using a blob field, but having trouble with inserting some data into it (like a file), you might want to check the MySQL environment varibale max_allowed_packet.  The max_allowed_packet variable can be found in your configuration file (usually /etc/my.cnf), and is usually set to something around 1 MB.  If you try to insert a binary file larger than 1MB, the MySQL insert will fail.  All that’s needed, is to change to max_allowed_packet to something larger, then, restart MySQL:

MySQL Max Allowed Packet

SanDisk 4GB Cruzer Freedom USB Flash Drive

I was the blessed recipient of two of these amazing flash drives from SanDisk for Christmas. I just thought I’d give a quick review in case anyone out there is thinking of purchasing this little drive. Mine were purchased from Amazon, and came out to only about $60 a piece.

SanDisk 4GB Cruzer Freedom USB Flash Drive

The drive comes with either a rubber keychain attachment (as show in the pic), or a similar rubber necklace. At first I was worried about the connection strength of the drive to it’s attachments (as I have been burned before by “loose” connections breaking off, resulting in a lost drive), but this connection is very sturdy. In fact, sometimes I have to strain myself to get the top off. I plugged this drive into my Ubuntu computer, and it was immediately recognized as “freedom”, which I thought was aptly appropriate. There was no DRM, no Windows only stuff, just a fast, 3.8 GB drive. Copying files worked great and so far the drives have been a joy to use.

Using Virtual Hosts with Apache and SSL Certificates

When we first started using our own server to host multiple client websites, one problem we commonly came across was “how can we host different virtual domains and different SSL certificates?” After some research, we came to the same conclusion you probably already know, because of the SSL protocol, you can’t use Virtual Hosts with SSL. This is because SSL is encrypted, and it must be read and un-encrypted before the requested domain name can be read by Apache, because… it is encypted.

So, how can you provide your multiple clients with Virtual Domains their own SSL and https:// address? You can:

  • Let them share your server’s SSL certificate, and server name (e.g. https://holleygrove.com/secure/CustomerName). This, unfortunately is a different domain name, so it may bring up a red flag to some shoppers, however, if you have a valid SSL certificate for your domain (holleygrove.com), the site will be valid and no security warnings will appear.
  • Redirect them to the https version of their domain name even though there is not a valid SSL certificate for their domain (or there is, but because of the SSL protocol, Apache cannot access it). This will present the user with a domain name/ SSL certificate mis-match (which is bad), but the URL will read https://CustomerName.

Both of the above solutions have compromises. The best way to get around this is to use a separate IP address specifically for your VirtualDomain. This will allow you to setup Apache to listen for your VitrualDomain… SSL (port 443) and HTTP (port 80) on this particular IP address. Below is a working code excerpt from Apache 2.2 for a VirtualDomain listening on a separate IP address:

 # IP Based Virtual Host - Example.com - IP:  192.168.1.1
NameVirtualHost 192.168.1.1:80
<VirtualHost 192.168.1.1:80>
        ServerAdmin support@holleygrove.com
        DocumentRoot /home/example/public_html
        ServerName www.example.com
        ServerAlias example.com *.example.com
        ErrorLog /etc/httpd/groups/example/logs/error_log
        CustomLog /etc/httpd/groups/example/logs/access_log combined
        #TransferLog /etc/httpd/groups/example/logs/access_log
        <Directory "/home/example/public_html">
                AllowOverride All
                Order allow,deny
                Allow from all
        </Directory>
</VirtualHost>

Make sure to change the above directive to match your IP and system configuration, and place it in your Apache’s configuration file. Any IP-based VirtaulHost directives, such as the one above, should be placed after any non-IP based (name based) VirtualHost directives.

Zebra Comedy

Paul Smith Zebra

From Sam’s Page.

Howto: Let Google Handle all your email!

For me, Linux hosting is great, for the most part it’s straight forward, secure, reliable, and fast.  But, there’s always been a sort of sore spot for me when administering my systems: email.  Email is arguably the hardest part of a server to setup… securely.  And for smaller sites and servers our email has been plagued by a host of problems, security holes, SPAM, getting falsely labeled as SPAM, mailbox sizes, and viruses to name a few.  With the advent of Google apps, the days of hosting your own mail servers can be a thing of the past.

To get started, simply go to http://google.com/a and sign up.  Google offers a basic edition, premier edition, and a pro-bono edition.  I’ve always used the basic edition and found it is more than adequate for smaller sites, but, if you’re so inclined, you may want to spring for the premier edition.  Simply click on the signup button:

Sign Up

Basic Edition

Fill out the required information.  In this example, I’m using a domain I’ve already registered with GoDaddy called theartisticweb.com.

Domain Name

Now you’ll need to create and administrator email account.  This is the main mail account that will be associated with our domain example.com.  I’ll create “admin”.  This can later be changed through the dashboard if you ever need to by adding another administrator and deleting this account.

Create Admin User

Create Admin User

We’ve now signed up our domain with Google apps.  The first thing we need to do is to validate our domain:

Domain Validation Notice

If you’ve used Google webmaster tools before, you’re familiar with the domain validation process.  Basically we just need to create an HTML file (in this case called googlehostedservice.html) on our webserver with the text from Google inside.  Just click domain validate:

Domain Name Validation Form

Create a blank HTML file called googlehostedservice.html and add the required text to it, and upload it to your domain’s root web folder.  Verify that you can read the link by clicking on it in your browser, then if all is good click verify.

The verification process is rather fast, so once you return to the dashboard, Google will probably have already verified your domain.  Now we can begin the email setup.

Click on the “Setup Email” link:

Google Apps Email MX records Form

Here you can choose what instructions Google will show you based on your DNS provider.  Ours is GoDaddy, so I select GoDaddy from the list, and follow the instructions.  Note: you must be using the nameservers of the company that is hosting your domain name in order for these insturctions to work.  If not, you will need to contact your domain name’s DNS provider to change these settings for you.  By default, domain names use the DNS servers of the company you purchased the domain name from, e.g. GoDaddy, so you should be ok unless you’ve changed the nameservers for your domain somewhere along the line.

Once you’ve entered the MX records exactly as shown (don’t forget a trailing “.” if applicable), click ok.  It should take anywhere from 10 minutes to a day or two to update the DNS settings for your domain and Google apps.  If you’ve done the steps correctly, then just be patient.  You can use dnstools.com to check the status of your MX records, or on a *NIX machine type

dig example.com MX

to get a reading on your MX records.  Once they’ve updated, you can then use Google’s server to handle all of your company’s email!  Presto!

Howto: Rotate VirtualHost Log Files with Logrotate

We have a Fedora 6 web server that, like most web servers, has quite a few virtual hosts.  We want our clients to keep their web server log data separate, so that if they want, they can view the server statistics for their website using awstats.  We’ve found the easiest way to do this is to enable separate log files for each virtual host.  That’s all fine and dandy, but after a while, these files can get pretty large.  In order to keep them from taking up too much space, it’s a good idea to use a program like logrotate to rotate out these logs for us.

With Fedora 6, logrotate comes installed automatically, but we could have installed it via yum as root:

yum install logrotate

Logrotate should have put an entry in /etc/cron.daily, and will then be run as a daily cron job automatically.  The Fedora package of logrotate will automatically rotate most of your system logs.  But, as we have some “unconventional” virtual host logs we’d also like to rotate, we’ll have to set those up manually.

To setup the rotation of the virutal host logs, you can cd to /etc/logrotate.d.   There you should see a file for apahce’s default logs called httpd.  Just copy or modify this file for each virtual host you have.  Any files in /etc/logrotate.d will be automatically read by logrotate when it runs.  That’s it!

Updating the Database from CFGRID

ColdFusion MX7 offers Flash Forms which is a very nice, new, and quick touch to any application. Unfortunately, it does have limitations that send developers like myself hunting for answers to keep the integrity of strong application development with an effortless and clean interface. Here is one example that set me back a few and left me extremely frustrated with Adobe Live Docs.

CFGRID is a very powerful tool when displaying records from any database because they eliminate the annoyance tables can tend to have when writing HTML. It’s just a different way of thinking though when building style into the simple idea of a clean record set that gets returned. I have come across this one too many times with using Flash Forms, “How can I make this presentation/application more efficient for the user?” Simple, by reducing the amount of steps it takes to add, edit, and manipulate data without giving a mess of confusion in one page. This is not so simple when it comes to CFGRID. There are a million examples of how to edit data within the grid, delete rows, insert new rows, even total a column’s values. But very few actually show how to edit the information in the grid and write back to the database leading to my frustration with documentation available for ColdFusionMX7 & MX6. This really only poses a problem to those of us that started coldfusion a little later then most.

There is hope though! It is actually documented in ColdFusion 5’s explanations/examples of CFGRID. It gives a few tags that are extremely powerful making two days of Google searching worth the five maybe ten lines of code it takes to accomplish this. Here is my example which we will call “licenses.cfm“:

In your Grid there are only but two to three statements needed to make columns and/or whole rows editable. The first one resides in your start tag. For example:

 

cfgrid name="AllLicenses" query="qAllLicenses" format="flash" sort="yes" height="200"
selectmode="edit"

Notice the last part. Selectmode is what makes your grid editable allowing you to select any area and change the data. Within your tag you can designate which columns to make editable. Here is an example of how to restrict editing:

 

cfgridcolumn name="LicenseID" header="License ID" width="50" display="no" select="no"

The select=”no” statement is an immmediate reference to “selectmode” and this columns particular state/function. This example shows how to allow for an edit in a given column:

 

cfgridcolumn name="LicenseAdd" header="Add" width="30" type="boolean" select="yes"

Simple enough. Keep in mind that without these “select” tags in each cfgridcolumnit will just default making all columns editable. For my case I wanted to assign hardware items multiple software licenses. My goal was to provide a “oneshot” that would display a little information about the box, it’s current list of licenses applied, and all available licenses to add. With respect to building it in one page for the user I wanted them to have the ability to select via “checkbox” any remaining licenses attaching them to that specific box. Without Flash Forms it is a pretty easy task but then you lose the power of clean interface elements on the fly. With them is a different story.

I inserted a new field into my inventory database within my Licenses table called “LicenseAdd“. This is of boolean type and has no purpose other than to temporarily tag each license for later review upon “submit”. There is really only one more part to consider at this point. How do we update the database depending on which licenses have been checked inside the ? It’s pretty easy actually! You want to build a cfloopthat moves through an array that is combined of all records selected from the grid for insertion. Like so:

 

cfif IsDefined("FORM.LicenseAdd")

cfloop from="1" to="#ArrayLen(FORM.allLicenses.LicenseID)#" index="i"

cfinvoke component="inventoryCollectionManager.items" method="insertLicenseLocations"

cfinvokeargument name="LicenseID" value="#FORM.allLicenses.LicenseID[i]#"

cfinvokeargument name="ItemID" value="#URL.ItemID#"

/cfinvoke

/cfloop

cflocation url="viewAllLicenses.cfm?ItemID=#URL.ItemID#"

/cfif

Depending on whether any boxes are checked in the designated column:

 

cfif IsDefined("FORM.LicenseAdd")

Start at one and go until the Length of the Array:

 

cfloop from="1" to="#ArrayLen(FORM.allLicenses.LicenseID)#" index="i"

Then perform this action(write to a table in your database):

 

cfinvoke component="inventoryCollectionManager.items" method="insertLicenseLocations"

cfinvokeargument name="LicenseID" value="#FORM.allLicenses.LicenseID[i]#"

cfinvokeargument name="ItemID" value="#URL.ItemID#"

/cfinvoke

Stop loop after insert and redirect back to that same page to show added licenses.

 

/cfloop

cflocation url="viewAllLicenses.cfm?ItemID=#URL.ItemID#"

/cfif

That is about it. For another example on this please visit:

http://cfsilence.com/blog/client/index.cfm/2006/2/2/Cant-use-CFGRIDUPDATE–Try-this

and

http://livedocs.macromedia.com/coldfusion/5.0/CFML_Reference/Tags41.htm