Posts Tagged 'Tricks'

September 26, 2012

Tips and Tricks - jQuery Lazy Load Plugin

In the late 90's, web pages presented their information in a relatively structured fashion, with little concern on how "pretty" the content looked. To a certain extent, that was a result of available technology and resources being a little more limited, but much of the reason was probably because we had no idea what was possible. We've come a long way, my friend. These days, it's tough to spend an hour online without coming across a gorgeous web site with huge animations, a pallet of every color possible, full-width backgrounds and high definition detail.

Those sites may be aesthetically pleasing, but they can be a big pain from a developer's perspective.

How much load does all of that stuff put on the server every time that web page is visited? As developers, it's our job to think about both what the visitor sees AND the visitor's experience in seeing it. Even the most beautiful sites will be ignored if a page takes too long to load. We spend hours optimizing every detail so users can fluidly browse without having to wait. It was in one of these optimization sessions that I discovered "lazy load."

To be honest, I wasn't too fond of the word "lazy" in the name, and I especially wasn't fond of having to explain to my boss that *I* wasn't being lazy ... The jQuery plugin is *named* "Lazy Load." Lazy Load effectively allows large pieces of content to stay in the backlog until they're needed. To give you an example of what that looks like, let's say you have a website with three humungous images, but they're all in different locations. Instead of pushing the entire load onto the user when they first land on your page, we can break them up and have them load only when the user goes to view them. We're not reducing the size of the web page; we're merely helping it work smarter.

Without Lazy Load, a normal web page loads each item when its page is visited. If a website has videos, music, images and some neat user interactivity applications, each of those items will load at the same time:

Lazy Load Illustration

If you take into consideration how large each of those items are, you can sense the problem. The user only has so much bandwidth to load these items, and something's gotta give. Usually, it means long loading times. We can't control how fast each user's ISP is, but we can reorder our items and let Lazy Load help us prioritize items and load the page more efficiently.

After we snag Lazy Load on Github (jquery.lazyload.js), we put our jQuery scripts in the <head> of our page:

<script src="jquery.js" type="text/javascript"></script> 
<script src="jquery.lazyload.js" type="text/javascript"></script>

Now that the plugin is available to us, we need to determine what we want to load lazily. Images are probably one of the most bothersome page elements, so let's apply Lazy Load to the images we load in the belazy class. In the <head> of your page (or in the footer if you prefer your JavaScript entries there), you'll add:

<script type="text/javascript">$("img.belazy").lazyload();</script>

As a result of that function, all image tags with a class of belazy will have Lazy Load run on them. This helps us ensure that we're not loading ALL of our images lazily. Now we need to choose which images we want to apply Lazy Load to.

Let's say the image tag of the largest image on one of our page looks like this:

<img src="bighonkingimage.png"/>

To have the lazyload function apply to it, we just have to make a couple tweaks:

<img class="belazy" src="bighonkingimage.png" data-original="bighonkingimage.png"/>

We added class="belazy" to trigger the lazyload function, and we added data-original="bighonkingimage.png" to line up with the formatting required by the newest version of Lazy Load (it's simply a repeat of the source).

When a user visits our page, bighonkingimage.png will load only when it's needed!

Pretty neat, eh?

-Cassandra

August 8, 2012

No iFrames! Dynamically Resize Divs with jQuery.

It's no secret that iframes are one of the most hated methods of web page layouts in the web development world — they are horrible for SEO, user experience and (usually) design. I was recently charged with creating a page that needed functionality similar to what iframes would normally provide, and I thought I'd share the non-iframe way I went about completing that project.

Before I get into the nitty-gritty of the project, I should probably unpack a few of the reasons why iframes are shunned. When a search engine indexes a page with iframes, each iframe is accurately recorded as a separate page — iframes embed the content of one we page inside of another, so it makes sense. Because each of those "pages" is represented in a single layout, if a user wanted to bookmark your site, they'd probably have a frustrating experience when they try to return to your site, only to find that they are sent directly to the content in one of the frames instead of seeing the entire layout. Most often, I see when when someone has a navigation bar in one frame and the main content in the other ... The user will bookmark the content frame, and when they return to the site, they have no way to navigate the pages. So what's a developer to do?

The project I was tasked with required the ability to resize only certain sections of a page, while asynchronously shrinking another section so that the entire page would always stay the same size, with only the two sections inside changing size.

Let's look at an example with two divs, side by side on a web page:

iFrame Tutorial

One div will contain a navigation menu to jump to different pages of the website (#sidebar), and the second div will contain all the content for that page (#content). If some of the elements in #sidebar are too long to read with the default width of the div, we want to let the user freely resize the two divs without changing the width of the page.

Our task is straightforward: When #sidebar expands in width, also expand the navigation and shrink #content along with the main content inside #content. If #sidebar shrinks, the navigation, #content and main content would respond accordingly as well:

iFrame Tutorial

It's a relatively easy concept to do with iFrames ... But then you remember that iframes are no longer cool (yes, there was a time long ago when iframes were cool). I decided to turn to my favorite alternative — jQuery — and the fix was actually a lot easier than I expected, and it worked beautifully. Let's run through a step-by-step tutorial.

1. HTML

Lay out your two divs:

<div id="sidebar"> 
<div class="sidebar-menu">
<!-- all your sidebar/navigational items go here -->
</div>
</div>
<div id="content">
<!-- all your main content goes here -->
</div>

2. CSS

Style your divs:

#sidebar {
       width: 49%;
}
#content {
width: 49%;
        float: left;
}

3. jQuery

Now that we have our two divs side by side, let's apply some jQuery magic. To do that, Let's include our jQuery files in the <HEAD> of our document:

<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>

Now that we have the necessary scripts, we can write our function:

<script type="text/javascript">
  $(document).ready(function() {
    $( "#sidebar" ).resizable({      
    });
    $("#sidebar ").bind("resize", function (event, ui) {
            var setWidth = $("#sidebar").width();
            $('#content).width(1224-setWidth);
            $('.menu).width(setWidth-6);
        });
  });
</script>

I know that might seem like an intimidating amount of information, so let's break it down:

   $( "#sidebar" ).resizable({      
   });

This portion simply makes the div with the ID of "sidebar" resizable (which accomplishes 33% of what we want it to do).

   $("#sidebar ").bind("resize", function (event, ui) {

By using the .bind, we are able to trigger other events when #sidebar is called.

            var setWidth = $("#sidebar").width();
            $('#content).width(1224-setWidth);

This is where the magic happens. We're grabbing the current width of #sidebar and subtracting it from the width you want your site to be. This code is what keeps your page stays the same width with only the divs changing sizes.

            $('.menu).width(setWidth-6);

This part of the code that expands the contents in the navigation along with #sidebar.

You can see a working example of iframe-like functionality with jQuery here: http://jqueryui.com/demos/resizable/

The only part you won't find there is the trick to adjust a corresponding div's size to make it grow/shrink with the first ... I had a heck of a time searching that on the web, so hopefully this quick tutorial will help other developers who might be searching for this kind of functionality!

- Cassandra

June 27, 2012

Cloudability: Tech Partner Spotlight

This guest blog comes to us from Cloudability, a featured member of the SoftLayer Technology Partners Marketplace. Cloudability is a cloud budget management service that helps companies manage their cloud spending, prevent overages, reduce waste and save money. In this video we talk to Cloudability Founder and CEO Mat Ellis about how the company developed, and we hear examples of how Cloudability is supporting and businesses money.

5 Things You Need to Know to Control Variable Infrastructure Costs

If you have on premise equipment, then your costs are fixed — you paid your money and now you own a fixed amount of hardware and software. The cloud, on the other hand, has variable costs due to two important features — you only pay for the services you use and it's scalable, providing the resources you need at any given time. By using a cloud infrastructure, you end up with what we call Variable Infrastructure Costs (VICs).

Most of SoftLayer's services meet the criteria for a VIC. You need an extra cloud server for a few hours? No problem. More disk? Done.

With great power, comes great responsibility, and the biggest problem with VICs is that they are just like a faucet: Leave it running, and the water bill can add up fast ... Not to mention all that waste! Unless you keep a close eye on VICs, you could find yourself in front of your CFO, pleading for your budget's life.

Cloudability was created to keep those costs under control, and in the course of working with our customers, we've come up with a simple five-point checklist of best practices:

1. Collation

Make sure you have insight to all your costs, create a single contract database, and review it regularly. Don't forget to include total cloud spending alongside your fixed contracts. Talk to your finance department, then drill your employees and tech teams to make sure you REALLY know the whole truth. There can be — and usually is — a disconnect in the organization about how much cloud is really being used.

2. Analysis

Get into the weeds to see why each project is spending what they are spending. Try to calculate some tangible metrics like cost per thousand web pages served or cost per new customer, and benchmark these against public data and common sense.

3. Organization and Rebalancing

Put each of your projects into one of four quadrants:

  1. High Spend/Low Efficiency
  2. High Spend/High Efficiency
  3. Low Spend/Low Efficiency
  4. Low Spend/High Efficiency.

Focus on the High Spend/Low Efficiency quadrant first. That's where you will find the easiest wins. Then, move onto the High Spend/High Efficiency quadrant where you'll find best practices to use for other projects. Then, if you have the time/resources, focus on the low spend projects and repeat.

4. Renegotiation

Contact your colleagues outside your department and compare unit prices, especially for things like bandwidth, co-lo and staff costs. Make sure you're in the top quartile for value (i.e. lowest costs). Renegotiate with vendors if you aren't, and plan to change vendors and staff when you can't the best value with your current resources.

5. Alignment

Understand your business objectives and get your roadmap tightly aligned. If you need some CAPEX to reduce operational expenses, then ask for it as part of the planning. You've got to spend money to make money right?

VICs can be easily manage once you understand where they're all coming from. After applying these five best practices into the way your business approaches cloud spending, you'll be well on your way. Cloudability's business was built to make the process a little easier and more automated for you, so if you want to use our tool to help you "cover your *aas," we'd love for you to try it out for free: https://app.cloudability.com/signup

-Mat Ellis, Cloudability

This guest blog series highlights companies in SoftLayer's Technology Partners Marketplace.
These Partners have built their businesses on the SoftLayer Platform, and we're excited for them to tell their stories. New Partners will be added to the Marketplace each month, so stay tuned for many more come.
May 23, 2012

Web Development - JavaScript - Creating a Sticky Menu

When designing websites, I like to focus on ease of use and accessibility for the end user. While creating your site to be friendly to screen readers and text-based browsers is a must, the accessibility I'm referring to is making it easy for your audience to navigate your site and perform certain common actions. By providing an easy interface for your users, you are immediately increasing your chances that they'll return for more of your site's goodness.

Thus far in our "Web Development" blog series, we've looked at JavaScript Optimization, HTML5 Custom Data Attributes, HTML5 Web Fonts and using CSS to style the Highlight Selection. In this post, we're going to create a "sticky" menu at the top of a page. As a user scrolls down, the menu will "stick" to the top and always be visible (think of Facebook's Timeline view), allowing the user quicker access to clicking common links. With some simple HTML, CSS and JavaScript, you can have a sticky menu in no time.

Let's start with our HTML. We're going to have a simple header, menu and content section that we'll throw in our <body> tag.

<header>
    <h1>My Header</h1>
</header>
<nav id="menu">
    <ul id="menu-list">
        <li>Items</li>
    </ul>
</nav>
<div id="content">
    Some content
</div>

For brevity, I've shortened the content I show here, but the working example will have all the information. Now we can throw in some CSS to style our elements. The important part here is how the <nav> is styled.

nav#menu {
    background: #FFF;
    clear: both;
    margin: 40px 0 80px 0;
    width: 99.8%;
    z-index: 2;
}
ul#menu-list li {
    border: solid 1px blue;
    list-style-type: none;
    display: inline-block;
    margin: 0 -3px;
    padding: 4px 10px;
    width: auto;
}

We have set the menu's background to white (#FFF) and given it a z-index of 2 so that when the user scrolls, the menu will stay on top and not be see-through. We've also set the list items to be styled inline-block, but you can style your items however you desire.

Now we get to the fun part – the JavaScript. I've created a class using Mootools, but similar functionality could be achieved using your favorite JavaScript framework. Let's examine our initialize method (our constructor) in our Stickit class.

var Stickit = this.Stickit = new Class({
    initialize: function(item, options) {
        // 'item' is our nav#menu in this case
        this.item = document.id(item);
 
        // The element we're scrolling will be the window
        this.scrollTarget = document.id(options.scrollTarget || document.window);
 
        // The 'anchor' is an empty element that will always keep the same location
        // when the user scrolls. This is needed because this.item will change and
        // we cannot rely on it for accurate calculations.
        this.anchor = new Element('div').inject(this.item, 'top');
 
        // The 'filler' is an empty element that we'll use as a space filler for when
        // the 'item' is being manipulated - this will prevent the content below from
        // jumping around when we scroll.
        this.filler = new Element('div').inject(this.item, 'after');
 
        // Set the styles of our 'filler' to match the styles of the 'item'
        this.setFillerStyles();
 
        // Initialize our scroll events – see the next code section for details
        this.initEvents();
    }
});

What we're doing here is grabbing our element to stick to the top – in this case, nav#menu – and initializing our other important elements. I'll review these in the next code section.

var Stickit = this.Stickit = new Class({
    ...
    initEvents: function() {
        var that = this,
            // Grab the position of the anchor to be used for comparison during vertical scroll
            anchorOffsetY = this.anchor.getPosition().y,
            // Grab our original styles of our 'item' so that we can reset them later
            originalStyles = this.item.getStyles('margin-top', 'position', 'top');
 
        // This is the function we'll provide as our scroll event handler
        var stickit = function(e) {
            // Determine if we have scrolled beyond our threshold - in this case, our
            // anchor which is located as the first element of our 'item'
            var targetScrollY = that.scrollTarget.getScroll().y,
                fixit = targetScrollY > anchorOffsetY;
 
            if (fixit &amp;&amp; that.cache != 'fixed') {
                // If we have scrolled beyond the threshold, fix the 'item' to the top
                // of the window with the following styles: margin-top, position and top
                that.item.setStyles({
                    'margin-top': 0,
                    position: 'fixed',
                    top: 0
                });
                // Show our (empty) filler so that the content below the 'item' does not
                // jump - this would otherwise be distracting to the user
                that.filler.setStyle('display', 'block');
                // Cache our value so that we only set the styles when we need to
                that.cache = 'fixed';
            }
            else if (!fixit &amp;&amp; that.cache != 'default') {
                // We have not scrolled beyond the threshold.
                // Hide our filler
                that.filler.setStyle('display', 'none');
                // Reset the styles to our 'item'
                that.item.setStyles(originalStyles);
                // Cache our values so we don't keep resetting the styles
                that.cache = 'default';
            }
        };
 
        // Add our scroll event to the target - the 'window' in this case
        this.scrollTarget.addEvent('scroll', stickit);
        // Fire our scroll event so that all the elements and styles are initialized
        this.scrollTarget.fireEvent('scroll');
    }
});

This method contains the meat of our functionality. The logic includes that we test how far the user has scrolled down on the page. If s/he scrolls past the threshold – in this case, the anchor which is located at the very top of the "stuck" item – then we set the menu to be fixed to the top of the page by setting the CSS values for margin-top, position and top. We also display a filler so that the content below the menu doesn't jump when we set the menu's position to fixed. When the user scrolls back to the top, the styles are reset to their original values and the filler is hidden.

To see a full working example, check out this fiddle. The Stickit class I created is flexible enough so that you can "stick" any element to the top of the page, and you can specify a different scrollTarget, which will allow you to scroll another element (besides the window) and allow the item to stick to the top of that element instead of the window. If you want to give that a try, you can specify different options in Stickit and modify your CSS as needed to get it working as you'd like.

Happy coding,

-Philip

March 27, 2012

Tips and Tricks - How to Secure WordPress

As a hobby, I dabble in WordPress, so I thought I'd share a few security features I use to secure my WordPress blogs as soon as they're installed. Nothing in this blog will be earth-shattering, but because security is such a priority, I have no doubt that it will be useful to many of our customers. Often, the answer to the question, "How much security do I need on my site?" is simply, "More," so even if you have a solid foundation of security, you might learn a new trick or two that you can incorporate into your next (or current) WordPress site.

Move wp-config.php

The first thing I do is change the location of my wp-config.php. By default, it's installed in the WordPress parent directory. If the config file is in the parent directory, it can be viewed and accessed by Apache, so I move it out of web/root. Because you're changing the default location of a pretty significant file, you need to tell WordPress how to find it in wp-load.php. Let's say my WordPress runs out of /webroot on my host ... I'd need to make a change around Line 26:

if ( file_exists( ABSPATH . 'wp-config.php') ) {
 
        /** The config file resides in ABSPATH */
        require_once( ABSPATH . 'wp-config.php' );
 
} elseif ( file_exists( dirname(ABSPATH) . '/wp-config.php' ) &amp;&amp; ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) {
 
        /** The config file resides one level above ABSPATH but is not part of another install*/
        require_once( dirname(ABSPATH) . '/wp-config.php' );

The code above is the default setup, and the code below is the version with my subtle update incorporated.

if ( file_exists( ABSPATH . 'wp-config.php') ) {
 
        /** The config file resides in ABSPATH */
        require_once( ABSPATH . '../wp-config.php' );
 
} elseif ( file_exists( dirname(ABSPATH) . '..//wp-config.php' ) &amp;&amp; ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) {
 
        /** The config file resides one level above ABSPATH but is not part of another install*/
        require_once( dirname(ABSPATH) . '../wp-config.php' );

All we're doing is telling the application that the wp-config.php file is one directory higher. By making this simple change, you ensure that only the application can see your wp-config.php script.

Turn Down Access to /wp-admin

After I make that change, I want to turn down access to /wp-admin. I allow users to contribute on some of my blogs, but I don't want them to do so from /wp-admin; only users with admin rights should be able to access that panel. To limit access to /wp-admin, I recommend the plugin uCan Post. This plugin creates a page that allows users to write posts and submit them within your theme.

But won't a user just be able to navigate to http://site.com/wp-admin? Yes ... Until we add a simple function to our theme's functions.php file to limit that access. At the bottom of your functions.php file, add this:

############ Disable admin access for users ############

add_action('admin_init', 'no_more_dashboard');
function no_more_dashboard() {
  if (!current_user_can('manage_options') &amp;&amp; $_SERVER['DOING_AJAX'] != '/wp-admin/admin-ajax.php') {
  wp_redirect(site_url()); exit;
  }
}
 
###########################################################

Log in as a non-admin user, and you'll get redirected to the blog's home page if you try to access the admin panel. Voila!

Start Securing the WordPress Database

Before you go any further, you need to look at WordPress database security. This is the most important piece in my opinion, and it's not just because I'm a DBA. WordPress never needs all permissions. The only permissions WordPress needs to function are ALTER, CREATE, CREATE TEMPORARY TABLES, DELETE, DROP, INDEX, INSERT, LOCK TABLES, SELECT and UPDATE.

If you run WordPress and MySQL on the same server the permissions grant would look something like:

GRANT ALTER, CREATE, CREATE TEMPORARY TABLES, DELETE, DROP, INDEX, INSERT, LOCK TABLES, SELECT, UPDATE ON <DATABASE>.* TO <USER>@'localhost' IDENTIFIED BY '<PASSWORD>';

If you have a separate database server, make sure the host of the webserver is allowed to connect to the database server:

GRANT ALTER, CREATE, CREATE TEMPORARY TABLES, DELETE, DROP, INDEX, INSERT, LOCK TABLES, SELECT, UPDATE ON <DATABASE>.* TO <USER>@'<ip of web server' IDENTIFIED BY '<PASSWORD>';

The password you use should be random, and you should not need to change this. DO NOT USE THE SAME PASSWORD AS YOUR ADMIN ACCOUNT.

By taking those quick steps, we're able to go a long way to securing a default WordPress installation. There are other plugins out there that are great tools to enhance your blog's security, and once you've got the fundamental security updates in place, you might want to check some of them out. Login LockDown is designed to stop brute force login attempts, and Secure WordPress has some great additional features.

What else do you do to secure your WordPress sites?

-Lee

March 13, 2012

Web Development - CSS - Highlight Selection

I immediately fell in love with CSS when we were introduced in late 2000. The ability to style a whole site outside the HTML was a fantastic concept and probably my first true introduction to separation of style and content. Put your words over here, and put how you display those words over there. So simple! Since then I have always been an advocate of cascading style sheets. Today's tip will involve an effortless addition that will have your readers say, "Ooooh. That's a clever little change."

I find that when I read articles and blogs online, I not only read with my eyes, I scan the page with my mouse. Especially if it's a wordy article or not styled in smaller columns, I highlight the text by clicking and dragging to help me maintain my focus. Up until recently, whenever you selected text that way in your browser, your operating system would choose the color of the background highlight. For Windows, this is generally blue. For OS X, this is whatever you've set your preferences to (which is light blue by default).

For those of you that use a newer version of Webkit (Chrome or Safari) or Gecko (Firefox), the site designer can determine what color to highlight your selection of text, and CSS has made it easy.

/* Webkit */
::selection {
    background: #972F2C;
    color: #FFF;
}
/* Gecko/Mozilla */
::-moz-selection {
    background: #972F2C;
    color: #FFF;
}

As of today, Webkit browsers are the only ones that support ::selection without browser prefixing. Firefox requires the -moz- prefix. Here we have set the highlight background color to "SoftLayer Red" (#972F2C) and made the text color white (#FFF). It should be noted that earlier versions of Webkit and Gecko did not support anything but the background property. There is still limited support for which CSS properties are allowed during selection. You are unable to change font-style, font-size, text-decoration and many other properties, but we can hope support for most of the properties will be available in the future.

This is pretty cool so far, but we can take it one small step further. Just like other selectors, we can apply the ::selection selector to other elements and style each one differently.

h2::selection {
    background: #B72E33;
    color: #FFF;
}
p::selection {
    background: #ACEFB2;
}
div::selection {
    background: #E4DB80;
}
span::selection {
    background: #C780E4;
    color: #FFF;
}

This produces the following:

Highlighting Example

Surprise your readers and give them some highlight goodness.

Happy coding!

-Philip

March 5, 2012

iptables Tips and Tricks - Not Locking Yourself Out

The iptables tool is one of the simplest, most powerful tools you can use to protect your server. We've covered port redirection, rule processing and troubleshooting in previous installments to this "Tips and Tricks" series, but what happens when iptables turns against you and locks you out of your own system?

Getting locked out of a production server can cost both time and money, so it's worth your time to avoid this. If you follow the correct procedures, you can safeguard yourself from being firewalled off of your server. Here are seven helpful tips to help you keep your sanity and prevent you from locking yourself out.

Tip 1: Keep a safe ruleset handy.

If you are starting with a working ruleset, or even if you are trying to troubleshoot an existing ruleset, take a backup of your iptables configuration before you ever start working on it.

iptables-save > /root/iptables-safe

Then if you do something that prevents your website from working, you can quickly restore it.

iptables-restore

Tip 2: Create a cron script that will reload to your safe ruleset every minute during testing.

This was pointed out to my by a friend who swears by this method. Just write a quick bash script and set a cron entry that will reload it back to the safe set every minute. You'll have to test quickly, but it will keep you from getting locked out.

Tip 3: Have the IPMI KVM ready.

SoftLayer-pod servers* are equipped with some sort of remote access device. Most of them have a KVM console. You will want to have your VPN connection set up, connected and the KVM window up. You can't paste to and from the KVM, so SSH is typically easier to work with, but it will definitely cut down on the downtime if something does go wrong.

*This may not apply to servers that were originally provisioned under another company name.

Tip 4: Try to avoid generic rules.

The more criteria you specify in the rule, the less chance you will have of locking yourself out. I would liken this to a pie. A specific rule is a very thin slice of the pie.

iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -d 123.123.123.123 -j DROP

But if you block port 22 from any to any, it's a very large slice.

iptables -A INPUT -p tcp --dport 22 -j DROP

There are plenty of ways that you can be more specific. For example, using "-i eth0" will limit the processing to a single NIC in your server. This way, it will not apply the rule to eth1.

Tip 5: Whitelist your IP address at the top of your ruleset.

This may make testing more difficult unless you have a secondary offsite test server, but this is a very effective method of not getting locked out.

iptables -I INPUT -s <your IP> -j ACCEPT

You need to put this as the FIRST rule in order for it to work properly ("-I" inserts it as the first rule, whereas "-A" appends it to the end of the list).

Tip 6: Know and understand all of the rules in your current configuration.

Not making the mistake in the first place is half the battle. If you understand the inner workings behind your iptables ruleset, it will make your life easier. Draw a flow chart if you must.

Tip 7: Understand the way that iptables processes rules.

Remember, the rules start at the top of the chain and go down, unless specified otherwise. Crack open the iptables man page and learn about the options you are using.

-Mark

February 20, 2012

Tips and Tricks - Remote Audio Over RDP in Windows 2008

I was working on my server the other night, and I found myself needing to get sound from my Windows 2008 box through an RDP (Remote Desktop Protocol) connection. Because we have a huge customer base with Windows 2008 installed now, I figured there may be someone else out there that would like to be able to hear sounds from their server on their local computer when connected, so I put together a quick walkthrough with how I got it to work:

Configuring Your Server

  1. Open Windows Services (Start -> Run -> Services.msc)
  2. Change the properties of the Windows Audio Endpoint Service and Windows Audio Service to "Automatic". If the services are not already started, you can manually start them at this time.
  3. Open Terminal Services ( Start -> Run -> tsconfig.msc)
  4. Right-click on the RDP-TCP connection and bring up its properties. Go to the "Client Settings" and make sure that on "Redirection Audio" is not disabled.
  5. Fully log out and log back into the RDP connection to the server. You will see a balloon error on your speaker icon that states "No Audio Output Device is installed."

Making Registry Changes

  1. You will now need to back up your registry and some registry changes.
  2. I want to reiterate the instruction to back up your registry ... As with most technical guides/walkthroughs, SoftLayer will not be held liable for any corruptions that may result from you attempting these changes. The next two steps will show how to quickly back up your registry.
  3. Log into your server on an account with Administrator rights, and open regedit (Start -> Run -> regedit)
  4. Export the current registry (from the "File" menu) and copy it to a location off of your server so you have it backed up.
  5. Locate the following key: HKEY_CLASSES_ROOT\AudioEngine\AudioProcessingObjects. This will contain several subkeys all each named with a GUID.
  6. Click on each subkey, then right-click and select "Permissions." You will then click on the "Advanced" button and the "Owner" tab. The current owner should be listed as "TrustedInstaller."
  7. Select the Administrative account and/or group from the list and click "OK" to change the ownership.
  8. Select the account you just chose and give it "Full Control," then click "OK."
  9. In the "Detail" box of each subkey, double-click on the DWORD value "MinOutputConnections" and change it from 1 to 0, then click "OK."
  10. Once you have done this for each subkey in HKEY_CLASSES_ROOT\AudioEngine\AudioProcessingObjects, you can close regedit and restart the Windows Audio and Windows Audio Endpoint services.

Configuring Your RDP Client

Now that you have everything ready on the server, you just need to make sure your RDP client recognizes the audio. Log off of the server so you can configure your RDP client. Open RDP, go to the "Options" menu, and under "Local Resources," select "Configure Remote Audio Settings." Select "Play on this Computer," and hit "OK." Voila! You now should be able to hear sound from your Windows 2008 RDP connection.

-Bill

January 9, 2012

iptables Tips and Tricks – Troubleshooting Rulesets

One of the most time consuming tasks with iptables is troubleshooting a problematic ruleset. That will not change no matter how much experience you have with it. However, with the right mindset, this task becomes considerably easier.

If you missed my last installment about iptables rule processing, here's a crash course:

  1. The rules start at the top, and proceed down, one by one unless otherwise directed.
  2. A rule must match exactly.
  3. Once iptables has accepted, rejected, or dropped a packet, it will not process any further rules on it.

There are essentially two things that you will be troubleshooting with iptables ... Either it's not accepting traffic and it should be OR it's accepting traffic and it shouldn't be. If the server is intermittently blocking or accepting traffic, that may take some additional troubleshooting, and it may not even be related to iptables.

Keep in mind what you are looking for, and don't jump to any conclusions. Troubleshooting iptables takes patience and time, and there shouldn't be any guesswork involved. If you have a configuration of 800 rules, you should expect to need to look through every single rule until you find the rule that is causing your problems.

Before you begin troubleshooting, you first need to know some information about the traffic:

  1. What is the source IP address or range that is having difficulty connecting?
  2. What is the destination IP address or website IP?
  3. What is the port or port range affected, or what type of traffic is it (TCP, ICMP, etc.)?
  4. Is it supposed to be accepted or blocked?

Those bits of information should be all you need to begin troubleshooting a buggy ruleset, except in some rare cases that are outside the scope of this article.

Here are some things to keep in mind (especially if you did not program every rule by hand):

  • iptables has three built in chains. These are for INPUT – the traffic coming in to the server, OUTPUT – the traffic coming out of the server, and FORWARD – traffic that is not destined to or coming from the server (usually only used when iptable is acting as a firewall for other servers). You will start your troubleshooting at the top of one of these three chains, depending on the type of traffic.
  • The "target" is the action that is taken when the rule matches. This may be another custom chain, so if you see a rule with another chain as the target that matches exactly, be sure to step through every rule in that chain as well. In the following example, you will see the BLACKLIST2 sub-chain that applies to traffic on port 80. If traffic comes through on port 80, it will be diverted to this other chain.
  • The RETURN target indicates that you should return to the parent chain. If you see a rule that matches with a RETURN target, stop all your troubleshooting on the current chain, and return the rule directly after the rule that referenced the custom chain.
  • If there are no matching rules, the chain policy is applied.
  • There may be rules in the "nat," "mangle" or "raw" tables that are blocking or diverting your traffic. Typically, all the rules will be in the "filter" table, but you might run into situations where this is not the case. Try running this to check: iptables -t mangle -nL ; iptables -t nat -nL ; iptables -t raw -nL
  • Be cognisant of the policy. If the policy is ACCEPT, all traffic that does not match a rule will be accepted. Conversely, if the policy is DROP or REJECT, all traffic that does not match a rule will be blocked.
  • My goal with this article is to introduce you to the algorithm by which you can troubleshoot a more complex ruleset. It is intentionally left simple, but you should still follow through even when the answer may be obvious.

Here is an example ruleset that I will be using for an example:

Chain INPUT (policy DROP)
target prot opt source destination
BLACKLIST2 tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:50
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:53
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:1010

Chain BLACKLIST2 (1 references)
target prot opt source destination
REJECT * -- 123.123.123.123 0.0.0.0/0
REJECT * -- 45.34.234.234 0.0.0.0/0
ACCEPT * -- 0.0.0.0/0 0.0.0.0/0

Here is the problem: Your server is accepting SSH traffic to anyone, and you wish to only allow SSH to your IP – 111.111.111.111. We know that this is inbound traffic, so this will affect the INPUT chain.

We are looking for:

source IP: any
destination IP: any
protocol: tcp
port: 22

Step 1: The first rule denotes any source IP and and destination IP on destination port 80. Since this is regarding port 22, this rule does not match, so we'll continue to the next rule. If the traffic here was on port 80, it would invoke the BLACKLIST2 sub chain.
Step 2: The second rule denotes any source IP and any destination IP on destination port 50. Since this is regarding port 22, this rule does not match, so let's continue on.
Step 3: The third rule denotes any source IP and any destination IP on destination port 53. Since this is regarding port 22, this rule does not match, so let's continue on.
Step 4: The fourth rule denotes any source IP and any destination IP on destination port 22. Since this is regarding port 22, this rule matches exactly. The target ACCEPT is applied to the traffic. We found the problem, and now we need to construct a solution. I will be showing you the Redhat method of doing this.

Do this to save the running ruleset as a file:

iptables-save > current-iptables-rules

Then edit the current-iptables-rules file in your favorite editor, and find the rule that looks like this:

-A INPUT -p tcp --dport 22 -j ACCEPT

Then you can modify this to only apply to your IP address (the source, or "-s", IP address).

-A INPUT -p tcp -s 111.111.111.111 --dport 22 -j ACCEPT

Once you have this line, you will need to load the iptables configuration from this file for testing.

iptables-restore < current-iptables-rules

Don't directly edit the /etc/sysconfig/iptables file as this might lock you out of your server. It is good practice to test a configuration before saving to the system configuration files. This way, if you do get locked out, you can reboot your server and it will be working. The ruleset should look like this now:

Chain INPUT (policy DROP)
target prot opt source destination
BLACKLIST2 tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:50
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:53
ACCEPT tcp -- 111.111.111.111 0.0.0.0/0 tcp dpt:22
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:1010

Chain BLACKLIST2 (1 references)
target prot opt source destination
REJECT * -- 123.123.123.123 0.0.0.0/0
REJECT * -- 45.34.234.234 0.0.0.0/0
ACCEPT * -- 0.0.0.0/0 0.0.0.0/0

The policy of "DROP" will now block any other connection on port 22. Remember, the rule must match exactly, so the rule on port 22 now *ONLY* applies if the IP address is 111.111.111.111.

Once you have confirmed that the rule is behaving properly (be sure to test from another IP address to confirm that you are not able to connect), you can write the system configuration:

service iptables save

If this troubleshooting sounds boring and repetitive, you are right. However, this is the secret to solid iptables troubleshooting. As I said earlier, there is no guesswork involved. Just take it step by step, make sure the rule matches exactly, and follow it through till you find the rule that is causing the problem. This method may not be fast, but it's reliable. You'll look like an expert in no time.

-Mark

December 5, 2011

Quick Tip: Copy and Paste from the DOS Prompt

Having worked in SoftLayer's technical support department for a few years now, I can tell you that the more information you provide us, the faster we can get you to a resolution. If you can show us exactly the problem you're seeing with details from when you see it, it's much easier for us to troubleshoot, so I wanted to post a quick blog on the heels of Todd's "Global Network: The Proof is in the Traceroute" post to help you get information to us much more easily.

Document Format
Many people consider a Microsoft Word document the lowest common denominator when it comes to formatting an attachment or file while others prefer plain text for everything. I always advocate the use of plain text. Plain text is universally accessible, it doesn't require a third-party application to view, it doesn't add funky encoding, and it uses monospaced fonts that format the text like you'd see in a command prompt if you were sharing troubleshooting results from ping and traceroute commands. It's quite unnecessary to take a screen capture of a ping or traceroute when you run it, and it's doubly unnecessary to paste that screen capture into a Microsoft Word document.

Copying Your Ping/Traceroute
The problem many Windows users run into is that it's not very clear how to copy text from the command prompt ... The familiar keyboard shortcuts for copying (CTRL+C) and pasting (CTRL+V) don't work from the DOS Prompt, so the screen capture route is usually the easiest to execute. There is an easy way to copy, though.

Microsoft documented the instructions you need, and I wanted to share them with SoftLayer customers here:

  1. Open the command prompt. If you're unsure how to do this, open the Start Menu, click Run, enter "cmd" (without the quotes) and click OK.
  2. Execute your command. Use "tracert softlayer.com" to follow along with this test.
  3. Right-click the title bar of the command prompt window, point to Edit, and then click Mark.
  4. Click the beginning of the text you want to copy.
  5. Press and hold down the SHIFT key, and then click the end of the text you want to copy (or you can click and drag the cursor to select the text).
  6. Right-click the title bar, point to Edit, and then click Copy.

Now the text is in the clipboard. You can paste it anywhere, including the body of a ticket. To preserve layout, I usually paste the text in Notepad and attach that file to the ticket. If you don't want to go through the hassle of opening Notepad, just paste the results into the comment field below.

If you enjoy reading quick tips like this one that can make life easier, be sure to check out KnowledgeLayer.

-Lyndell

Bonus tip: If you want to submit your traceroute in a comment on this blog without losing the mono-spaced formatting, surround the pasted content with the <code> and </code> tags.

Subscribe to tricks