About Chris Gilligan

I’ve been building websites since the early days of the world wide web. My background is in publishing, document management, graphic design, corporate training and video production.
Author Archive | Chris Gilligan

Farm to Table Restaurant Website

Joe Naturals Farm Store Cafe is a “farm to table” cafe and natural foods store located in historic Leiper’s Fork, near Franklin, TN. The owners contacted me through a fellow farmer with whom I have worked on several web projects.

Joe Natural's website

The website project was languishing, after being abandoned by a designer who lacked knowledge of WordPress template coding. The site needed better integration with WordPress, including text-based navigation and replacement of scanned layout comps, which were being used for page display & navigation.

I reworked the stylesheet to replace image-based text with CSS styled text, integrated WordPress navigation, and then added a few WordPress plugins.

I also worked with the farmers’ social media person to add social media links and integrate Facebook “Likes” and cross publishing from the WordPress blog to the Facebook Fan Page.

Incoming search terms for the article:
Comments { 0 }

Apache and MySql Performance Tuning for High Traffic Website

SoccerNews.com is a high traffic WordPress site with over 600,000 unique visitors and over 2,000,000 page impressions per month. It is a content republisher and aggregator, presenting custom XML feeds for (what else?) soccer news from all over the world. The site has a very active user base, providing content in the forms of editorials and comments on news items. Advertising and sponsored referrals provide the revenue stream.

SoccerNews.com website

SoccerNews.com website

I was contacted by the publisher after responding to a plea for assistance in a WordPress.org support forum. Though the site was running on a dedicated server with 8GB RAM, it was crashing frequently under load. The developer tried implementing APC Alternative PHP Cache and W3 Total Cache, but these measures turned out to be incompatible with some of the custom PHP code and the software architecture of the server. Haphazardly implementing randomly suggested “solutions” had actually made the problems worse, resulting in an “own goal” that brought down the server.

I did an assessment of the software, hardware and traffic load and found that there were many improvements to be made. Among the changes:

  • Implemented a Stateful Packet Inspection firewall and Login Failure Daemon to block malicious IP addresses, malware servers, bad bots, content scrapers, etc. Many of the problems leading to site crashes were due to constant bad bot traffic, security probes and Denial of Service attacks. Connection Tracking in the firewall now limits the amount of resources a single legitimate IP address can monopolize, in addition to blacklisting attackers.
    • This is the first step to proper web server performance in today’s Internet climate. Popular sites that do not have a solid security and load balancing strategy are subject to crippling traffic from the Internet’s millions of malicious and compromised servers and personal computers.
  • Reconfigured Apache web server, PHP and MySQL to better utilize the server’s horsepower. Default configurations were limiting the number of concurrent user sessions the server could handle. Changed PHP to run as FastCGI (fcgid) and recompiled Apache to better handle the needs of a high traffic WordPress site. Configured a large MySQL table and query cache based on performance and load testing.
  • Configured a self-hosted Content Distribution Network, page cache, browser cache, and object cache with the WordPress plugin, W3 Total Cache. Due to the sheer number of ad scripts being served per page, there were inevitable JavaScript and PHP conflicts, but W3TC is very flexible and was able to handle the task.
  • Suggested a scheduled, offsite backup strategy that would utilize existing resources, and eliminate the need for a 3rd-party backup solution that was causing more load issues and costing $45.00 per month.
Now the site is stable and fast, and is ready for very high traffic. With World Cup Brazil coming up in 2014, the site will definitely see a huge amount of users. Future plans include moving the Content Distribution Network to an external provider, and possibly changing the architecture of the server to simplify the background processes and implement APC Alternative PHP Cache, or a caching web server front end.

Results? I’ll let the publisher speak to that!

The site has been as good as “flawless” since, with no downtime, and we couldn’t be happier. Everything is running smoothly and it’s a great relief knowing that we made the site faster, safer and more reliable. The site feels a lot more stable and faster. So you’ve done a great job. 

– Kim Vincenzius, StarScape LLC

Incoming search terms for the article:
Comments { 0 }

Tuning Apache and MySQL for Best Performance in a Shared Virtual Hosting Environment

Web hosting has changed dramatically in the last few years. The majority of accounts are now running PHP scripts and MySQL, whereas in the past most accounts were only serving static HTML files. This presents challenges in security as well as performance tuning.

It is impossible to predict whether a certain configuration will work properly for a given server, unless the hardware, software, accounts, network and traffic are identical to a previously configured server… therefore it is impossible to give a configuration which will cover all applications.

Firewall Unnecessary Traffic from Affecting the Server

Before you begin performance tuning, please consider using a stateful packet inspection (SPI) firewall & login failure daemon (LFD) for your server: ConfigServer Firewall is an excellent free firewall & lfd. This will help prevent brute force probes, port flooding, DDOS, etc. If you have 600 virtual hosts running on a server, it is very likely that the server is experiencing constant malicious exploits, especially if you are also running email servers on the same IP addresses.

Tune Apache the Sane Way (Requires Basic Math Skills)

If you wish to tune your Apache MPM settings, you should consider following this method:
https://telvps.com/clients/knowledgebase/25/HOW-TO-Optimize-Apache-for-Low-Memory-Usage.html
(the formula works well for any level of traffic and memory).

MySQL Tuning Is More Difficult: Trial and Error

To test your MySQL cache variables, you may try mysqltuner: https://github.com/rackerhacker/MySQLTuner-perl

This script will analyze MySQL performance and make suggestions regarding your my.cnf configuration. If you are running MySQL 5 or later, the configuration statements can be in the following form (example from one of my servers):

[mysqld]
safe-show-database
net_buffer_length = 1M
max_allowed_packet = 4M
myisam_sort_buffer_size = 24M
sort_buffer = 8M
key_buffer = 32M
table_cache = 1000
query_cache_size = 128M
thread_cache_size = 8
innodb_buffer_pool_size = 22M
join_buffer_size = 12M
tmp_table_size = 64M
max_heap_table_size = 32M
max_connections = 85

This is for example only! table_cache should be set a little higher than the total number of tables (sum of MYISAM,INNODB,MEMORY etc.), as reported by mysqltuner. If you anticipate adding more virtual hosts, or clients adding more databases or tables, you will need to raise table_cache value.

Follow the recommendations from the Apache tuning, and then follow the recommendations of the mysqltuner script. The apache tuning will give you the number of maxclients, and from this you will know the appropriate beginning value for [mysqld] maxconnections. Begin with maxconnections set slightly higher than maxclients.

Take Time to Get a Realistic Assessment of MySQL Performance

If you have a PHP opcode and database caching strategy (such as APC) implemented on your web server and for your PHP script packages, you will be able to lower maxconnections, based on the information you receive from mysqltuner after 24-48 hours of steady traffic. For example, I have a server with Apache set to 256 maxclients, but the MySQL maxconnections set to 200, because many web requests do not require direct interaction with the MySQL server.

Take a look at “Highest usage of available connections”, and lower maxconnections accordingly. It is safe to lower maxconnections to a number slightly above the reported highest usage. Doing so will allow you to set higher values for the individual cache settings which affect the thread cache size, because the total thread buffer memory size is multiplied by maxconnections. Feedback is available in the reports for “Total buffers” and “Highest usage of available connections”.

After you have the proper settings for maxclients and maxconnections, restart httpd and mysqld. Wait 1 hour, and run mysqltuner to see if there are any recommended changes. Mysqltuner will show you the maximum memory which will be used by mysql. You should adjust config variables to take up no more than 60% of total RAM. Wait 24-48 hours and run mysqltuner again.

Example mysqltuner results:

-------- Storage Engine Statistics -------------------------------------------
[--] Status: -Archive -BDB -Federated +InnoDB -ISAM -NDBCluster
[--] Data in MyISAM tables: 2G (Tables: 748)
[--] Data in InnoDB tables: 20M (Tables: 76)
[--] Data in MEMORY tables: 1M (Tables: 1)
[!!] Total fragmented tables: 55

-------- Performance Metrics -------------------------------------------------
[--] Up for: 15h 7m 18s (1M q [31.195 qps], 105K conn, TX: 7B, RX: 285M)
[--] Reads / Writes: 63% / 37%
[--] Total buffers: 390.0M global + 18.6M per thread (200 max threads)
[OK] Maximum possible memory usage: 4.0G (66% of installed RAM)
[OK] Slow queries: 0% (13/1M)
[OK] Highest usage of available connections: 25% (51/200)
[OK] Key buffer size / total MyISAM indexes: 72.0M/1.1G
[OK] Key buffer hit rate: 99.9% (1B cached / 1M reads)
[OK] Query cache efficiency: 78.2% (967K cached / 1M selects)
[OK] Query cache prunes per day: 0
[OK] Sorts requiring temporary tables: 0% (0 temp sorts / 74K sorts)
[OK] Temporary tables created on disk: 20% (7K on disk / 38K total)
[OK] Thread cache hit rate: 99% (294 created / 105K connections)
[OK] Table cache hit rate: 84% (1K open / 1K opened)
[OK] Open file limit used: 71% (1K/2K)
[OK] Table locks acquired immediately: 99% (684K immediate / 686K locks)
[OK] InnoDB data size / buffer pool: 20.2M/28.0M

-------- Recommendations -----------------------------------------------------
General recommendations:
Run OPTIMIZE TABLE to defragment tables for better performance
MySQL started within last 24 hours - recommendations may be inaccurate
Enable the slow query log to troubleshoot bad queries

I suggest you NOT enable the slow query log unless the Slow Queries result is very high. Slow Queries result % will be somewhat high if MySQL has run for less than 24 hours.

Incoming search terms for the article:
Comments { 0 }

APC Cache Considerations for Virtual Hosting Environments

APC cache does not work well in a virtual hosting environment unless PHP is running as FCGID, and every individual virtual host has a unique PHP.ini and a unique fcgiwrapper. This is not the case with many virtual hosting environments because the memory and CPU requirements are too great.

Also, APC user cache on a shared hosting server may not work properly, because several accounts may run similar PHP script packages, causing conflicts if scripts are named the same but contain different source code. e.g. if several users are running different versions of WordPress or Joomla, the code in each version will be different, but a cached script may be accessed by several different accounts. Obviously a very bad thing!

I suggest using Virtualmin for a shared hosting environment with APC cache, because it does allow to set php.ini and fcgiwrapper for every individual virtual host, and so to set an individual configuration for APC per virtual server. However with 200+ virtual hosts all running PHP script packages, as is the case with a commodity shared hosting server, this will use a lot of memory, and you will need somewhere in the neighborhood of 10-30GB apc.shm_size if you attempt to configure a single APC cache for the entire server.

My web hosting server is for a small number of personal clients, and so I adjust the APC settings for each individual account, depending on the number and type of PHP script packages running on the account. These accounts are all administered by myself, not by the clients.

I do not think APC is the correct cache for most shared web hosting servers, given the number of virtual hosts. You will probably have better results if you remove APC and concentrate on Apache performance tuning and MySQL cache.

If your clients are adamant in their requests to use APC cache, you may wish to move them to a different server which can properly handle their needs. Virtualmin is a very good choice for this, as it allows individual accounts to be configured with individual php.ini and fcgiwrapper, or even different versions of PHP. Of course, because this will require greater management, it should be charged as a premium service.

If you wish to enable APC on a commodity web hosting server, you may try the following method to selectively enable APC per directory:
http://www.php.net/manual/en/ini.php

 

Incoming search terms for the article:
Comments { 0 }

Remote publishing to WordPress from Facebook via RSS

Most WordPress developers know you can use one of several plugins to publish from WordPress to a Facebook wall, app or fan page. Did you know you can also do the opposite? You can publish from Facebook to WordPress by using the FeedWordPress plugin and the RSS feed from your fan page. This can be handy for clients who want to keep their site updated with blog posts, or share links and information, but don’t necessarily want to spend the time to post with WordPress.

Let’s face it, Facebook is convenient to use to share a link, upload small photos and video, or write a brief update.

Your Blog is Hungry

FeedWordPress is a plugin that pulls content from an RSS feed and publishes articles as WordPress posts. It is somewhat complex to set up properly, so I won’t go into that here. It’s up to you to figure it out, but it is very useful for adding non-copyright or permitted content to your site or a client’s site. For instance, I use it to publish bicycle manufacturer’s RSS feeds to a local bike shop’s WordPress site. You can also use it to create a scraper site, but you wouldn’t do that, would you?

Connect WordPress to Facebook

Using the plugin Simple Facebook Connect, your client can publish WordPress posts to a Facebook fan page.  I suggest you install Simple Facebook Connect and learn how to set up a simple Facebook App using the plugin’s easy instructions. This will allow your website to use Facebook authentication to Publish to Facebook, allow comments by logged in Facebook users, etc.

Creating an App instead of a Fan Page or Business page may suit your needs. Give it a try if you have not already set up a Facebook Page. If you use SFC, don’t set it to automatically publish to Facebook, or you may create a publishing loop. Leave it set to manual publishing and you’ll have an extra Publish button in the post editor for that purpose.

Setting up the Facebook RSS Feed

If your client would like to use Facebook’s simple, highly available, multi-device platform to publish content to a WordPress website, you will need a Facebook page or app’s RSS feed.

Facebook Fan Pages or Business Pages are for groups or businesses. If you build websites, you have probably set these up for several clients already. But to make the RSS feed from the page available to RSS readers and aggregators, you must change a few settings:

  • Edit Page > Manage Permissions
  • Uncheck Only Admins can See Page
  • Age Restrictions: None
  • Country Restrictions: None

Uncheck All:

  • Users can write or post content on the wall
  • Users can add photos
  • Users can add tags to photos
  • Users can add videos

This will make your wall posts available to the general public, because users with restricted privacy settings cannot post to your wall (they can still comment on your posts).

Now you can click the Subscribe by RSS link on your page, and the RSS feed will not display the dreaded “Facebook Syndication Error”:

You probably reached this page by entering the guide of a syndicated error message into the location bar of your browser. This probably means that you can’t see the feed that you were trying to access. This is probably because the owner of the feed changed his or her privacy settings or deleted content on the feed. You may be able to get access to the feed by contacting the owner of the content being syndicated in that feed.

You will get a RSS URL: http://www.facebook.com/feeds/page.php?id=195534004499&format=rss20

If your feed’s language needs to be adjusted, for instance if your site is hosted in Netherlands but your audience is in U.S., you will need to add a locale parameter to the feed URL: http://www.facebook.com/feeds/page.php?id=195534004499&format=rss20&locale-en_US

Try it in Firefox or NetNewsWire or any RSS Reader to see if you get a valid feed. If you see Facebook Syndication Error, then go back and edit your page’s permissions (see above).

If your site is hosted in a locale different from the locale of your Facebook page (e.g. your host is located in Europe, but your Facebook page is for North America), then you should use the resolved IP address for Facebook for your locale. You can find this IP address from a terminal window with the ping command. Otherwise, Facebook.com will resolve to the IP address and language for your host server. This causes synchronization issues and may cause a sync timeout which can block your pages from loading.

FeedWordPress Syndication

OK, now you have a valid feed. Add it to FeedWordPress. The settings you may wish to change:

Posts & Links >

  • Permalinks point to: The local copy on this website
  • Relative URIs: leave relative URIs unresolved
  • Formatting filters: Expose syndicated posts to formatting filters

Now, you should have a valid RSS feed and a properly configured Syndication system.Log in to Facebook and go to the app or page (easy way is to type the name into Facebook search bar at top).Share a Link, paste the URL of the page you want to feature, e.g. http://www.extremevisionhomes.com/

Edit the fields in the Link content by clicking on them. Or, you can upload a photo or video. But be sure to add a tagline to “Say something about this…” This line becomes your Title in the RSS feed or WordPress post. Otherwise you will see a generic “Your Client’s Facebook Wall 07/12/2011 15:35:43″ as the title.

And on the client’s site, you will see this:

You may want to set up a WordPress Category for these posts. FeedWordPress can be configured to post to a specific Category, add Tags, etc. You might even separate these posts from the main blog page, or style them in your WordPress theme via CSS or a Category Template.

Incoming search terms for the article:
Comments { 2 }

Cpanel Mailman mailing lists: cannot manage lists after migrating to new host

We recently migrated 2 Cpanel servers to VPS. Most things migrated properly and without incident. However, Mailman mailing lists were the exception.

Mailing lists appear to have migrated properly, as they show up under WHM and Cpanel and usr/local/cpanel/3rdparty/mailman/bin/list_lists

However, when cpanel user clicks Manage link, the following message appears:

cpanel1.hosting.com mailing lists – Admin Links
No such list listname_domainname.com
There currently are no publicly-advertised Mailman mailing lists on cpanel1.hosting.com.To visit the administrators configuration page for an unadvertised list, open a URL similar to this one, but with a ‘/’ and the right list name appended. If you have the proper authority, you can also create a new mailing list.

This turned out to be a permissions issue:

root@cpanel1 [/usr/local/cpanel/3rdparty/mailman/bin]# ./check_perms

--snip--
directory permissions must be 02775: /usr/local/cpanel/3rdparty/mailman/.../list_domain.com/...
--snip--
Problems found: 2999

# ./check_perms -f

FIXED!!!

Incoming search terms for the article:
Comments { 2 }

E-Commerce Magazine Subscription Website

Light Sport & Ultralight Flying Magazine needed an easy-to-manage e-commerce solution, coupled with Content Management and slideshows.

I used Joomla plus VirtueMart, and SlideShowPro to give them a sophisticated system that is simple to use.

Light Sport & Ultralight Flying Magazine website

The magazine has been in circulation since 1975, so the publishers know how to survive and thrive. Online sales & subscriptions give the print magazine a fighting chance against online outlets in a tight niche market.

Incoming search terms for the article:
Comments { 0 }

Apache config for Worker MPM vs Prefork MPM

Some installations of Apache will have been compiled to work with either Prefork or Worker MPM, but most by default are compiled only to work with Prefork. Changing to Worker MPM may allow your server to handle much higher traffic, more user sessions, with less RAM use. Your site or server will not scale well if it is running Prefork MPM. Worker is a bit more difficult to set up properly, and has some restrictions regarding functionality of PHP scripts.

  • To determine which MPM is running:
    /usr/sbin/apachectl -l
    • If you see worker.c in the list of loaded modules, your Apache is running Worker MPM. If prefork.c, it is running prefork.
  • To determine if apache has Worker MPM compiled in:
    /usr/sbin/httpd.worker -l
    • If you see worker.c in the list of compiled-in modules, Apache can run Worker MPM.

Here is some useful info to help if your installation of Apache will work with Worker MPM:

  • Un-Comment HTTPD=/usr/sbin/httpd.worker in /etc/sysconfig/httpd
  • restart apache
  • do some performance testing and raise your worker server and thread limits to sane levels in httpd.conf

If you need to recompile Apache and PHP, then you should do more research. Recompiling is not a trivial process.

I found that my server had much better memory usage under Worker MPM, however:

  • some scripts (squirrelmail, phpmyadmin) do not work on a per-domain basis and must be run direct to the actual server process with symlinked directories. This is much more efficient but less convenient for virtual domain owners
  • some /dev processes took on strange group permissions, getting the gid of the first user in the apache group.
  • browser caching was not well supported… the dreaded “blank screen between page loads” occurred more frequently under Worker MPM than Prefork MPM… also login/logout was sketchy on some sites… not sure why but my guess is that sessions may not be quite persistent using Worker vs Prefork due to cookie confusion… possible that multi-threading does not track cookies well.
More testing will be necessary to determine whether Worker MPM is a benefit on my server.
Incoming search terms for the article:
Comments { 0 }

Recursive chmod Tricks

Recursively chmod only directories
find . -type d -exec chmod 755 {} \;

Similarly, recursively set the execute bit on every directory
chmod -R a+X *
The +X flag sets the execute bit on directories only

Recursively chmod only files
find . -type f -exec chmod 644 {} \;

Recursively chmod only PHP files (with extension .php)
find . -type f -name '*.php' -exec chmod 644 {} \;

Incoming search terms for the article:
Comments { 1 }

Public Art Non-Profit Website

Mark Making is a Chattanooga non-profit with a mission to enhance the town with public art and to engage the public in the creation and production of art, not merely it’s appreciation or exhibition.

Mark Making website

This project was yet another “rescue effort” to save a dying website that had been abandoned by a previous developer. Knowing how artists can be very particular about visual design and information architecture, I was a little apprehensive to take on this project… but I soon found some new PHP and JavaScript code to make WordPress behave as desired.

  • Search Engine Optimization
  • Fancybox JavaScript modal windows for YouTube, image slideshows, audio, video and PDF
  • Google Web Fonts for a handcrafted look
  • Advanced Custom Fields for intuitive addition of media player icons and project metadata
Incoming search terms for the article:
Comments { 0 }