The Problem
Sometimes when upgrading VMware, I noticed that I can no longer share directories between my local file system and the VMs file system.
In an effort to get shared folders working, I would then go to the following location in VMware:
Virtual Machine -> Sharing -> Sharing Settings …
I would accurately see the folders I want to share and I would see that Shared Folders is “ON”. In an attempt to re-share the folders I toggled Shared Folders to “OFF”. I then toggled it back to “ON” and noticed the following error:
Unable to update run-time folder sharing status: Unknown error
The Solution
The problem is related to VMware tools and you will need to reinstall it. Here are the steps you should follow:
1. Open up VMware
2. Go to:
Virtual Machine -> Update VMware Tools
3. Click “Install” button
4. It will automatically download the VMware Tools package. When the package is completed downloading double click the *.tar.gz file to untar all it’s contents.
5. Go to the recently expanded folder (you might need to put a different path to where it actually downloaded the distribution):
cd ./vmware-tools-distrib/bin/
6. Change to root:
sudo -s
7. Remove current VMware Tools:
./vmware-uninstall-tools.pl
8. Reinstall:
cd ..
./vmware-install.pl
Use all the default values by simply hitting the enter key.
The above photo was generated using FaceProject, a PHP class that takes a photo of a person and generates a stylized and framed version of it. I spent last night creating FaceProject, simply to toy around with the GD library and came up with what I believe a pretty cool looking photo.
The project is currently hosted on GitHub: FaceProject
The photo above was created from this original photo:
Email2Image is a PHP library that I wrote to securely convert email addresses to
PNG images. The project is hosted on GitHub here:
https://github.com/jesseforrest/Email2Image
This basic example will show how to select the font to be used and output an image for the email address example@example.com.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php require_once 'Email2Image.php'; $email2Image = new Email2Image(); $email2Image->setFontPath('./fonts/'); $email2Image->setFontFile('tahoma.ttf'); $email2Image->setFontSize(12); $email2Image->setWidth(400); $email2Image->setHeight(300); $email2Image->setBackgroundColor('293134'); $email2Image->setForegroundColor('668aaf'); $email2Image->setHorizontalAlignment(Email2Image::MIDDLE); $email2Image->setVerticalAlignment(Email2Image::MIDDLE); $email2Image->setEmail('example@example.com'); $email2Image->outputImage(); |
The above code will output the following image:
Advanced examples using encryption and decryption are available at the above listed GitHub page.
This function accepts a string that contains a hexadecimal color (i.e. “5DBA00″) and returns a string containing a different color that can be used as it’s compliment. A common usage is if you have a background color and you want to find a compliment color that can be used for the font in the foreground.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php /** * Returns a hex color string which compliments the passed in 6 character * hex string * * @param string $hexColor The 6 character hex string * * @return string */ function getComplimentColor($hexColor) { $rHex = sprintf("%02X", round(255 - (hexdec(substr($hexColor, 0, 2))))); $gHex = sprintf("%02X", round(255 - (hexdec(substr($hexColor, 2, 2))))); $bHex = sprintf("%02X", round(255 - (hexdec(substr($hexColor, 4, 2))))); return $rHex . $gHex . $bHex; } |
Here is an example of how to use the function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php $originalColor = '5DBA00'; $complimentColor = getComplimentColor($originalColor); ?> Main Color: #<?php echo $originalColor; ?> <div style=" margin: 8px; width: 100px; height: 100px; background-color: #<?php echo $originalColor; ?>;"> </div> Compliment Color: #<?php echo $complimentColor; ?> <div style=" margin: 8px; width: 100px; height: 100px; background-color: #<?php echo $complimentColor; ?>;"> </div> |
The above example will output the following:
Overview
This article explains how to configure a production web server with CentOS Linux, Apache, MySQL, and PHP. It will also explain how to harden the system to protect from typical intrusions. All steps are required unless otherwise stated as “Optional”. Please read the steps thoroughly prior to doing them, since doing them incorrectly can leave the system in an unstable or unusable state.
Prerequisites
You should be proficient in getting around a Linux operating system. You should be familiar with the vi text editor for Linux. You should know common vi commands to open, insert, and save documents since they are not listed in this article. You should have a basic understanding of what a LAMP system is.
Problems or Feedback?
If you run into problems while running the following steps, please post comments below. I will try my best to help you get the issue(s) squared away, plus we can open it to the community for brainstorming. This article is by no means perfect, so it’s always good to hear feedback too. If you feel like something should be added to this article, please let me know.
Install Operating System
First you will need to get a server pre-installed with the latest stable release of CentOS. Most hosting companies do this step for you. However, installing the CentOS operating system is outside the scope of this article. Once that is done, you must SSH into the machine as the root user:
# ssh root@<new_server_ip_address>
Note: Any line that starts with a “#” symbol is used to denote entering text into a terminal window. Do not actually type the “#” symbol.
Tip: I recommend storing your root password in a safe place, such as PasswordSafe.
Update Yum and Install Initial Packages
We will be using Yellowdog Updater Modified (yum) as our package management utility. After you SSH into the web server as root, you will need to run the following commands to update the system:
# yum -y update
# yum -y groupinstall "Development Tools"
# yum -y install zlib-devel
# yum -y install httpd openssl-devel openssl mod_ssl vsftpd rpm-build rpm-devel autoconf automake lynx gcc
# yum -y install mysql mod_auth_mysql mysql-devel mysql-server
# yum -y install mod_python python python-devel
# yum -y install php-devel php php-common php-gd php-mcrypt php-mhash php-xml php-xmlrpc php-domxml php-gd php-mbstring php-mysql php-ncurses php-pear
# yum -y install sendmail sendmail-cf
# yum -y install wget
# yum -y install yum-utils
# yum -y install yum-plugin-replace
# yum -y install vim-X11 vim-common vim-enhanced vim-minimal
# yum -y install iptables
# yum -y install nmap
# yum -y install vixie-cron
Setup host access
We need to setup host access (TCP_WRAPPERS). There are two host access files (/etc/hosts.allow and /etc/hosts.deny) that are part of the TCP_WRAPPER package. This makes it possible to allow or deny access to certain services based on the IP. We need to edit the hosts.allow and hosts.deny files:
Run the following command to edit the file in vi text editor:
# vi /etc/hosts.allow
Paste the following into the file and then save the file:
sshd:ALL
vsftpd:ALL
sendmail:ALL
Tip: I recommend limiting access to your production servers based on specific IP addresses. This helps to prevent intruders from getting access to your server. For example, let's say you have an office IP address of 55.55.55.55, you would make the sshd line look like this:
sshd:55.55.55.55
You can enter multiple IP addresses also (separated by spaces).
Run the following command:
# vi /etc/hosts.deny
Paste the following into the file to deny all other services and then save the file:
ALL:ALL
Create User Account
Create a user account that you will use to log in to this server. Try to select a name that is distinct from your website. For example, if your website is mywebsite.com, do not make your username called mywebsite. In this example, we will use the username jesseforrest. You will want to replace jesseforrest with a more logical username that fits your needs. This account will be used for SSH connections.
# adduser jesseforrest
# passwd jesseforrest
Enter in a password and hit enter.
Retype the password and hit enter.
Tip: Make sure to save the username and password in your PasswordSafe.
Allow the user jesseforrest to “su -” into the root user:
# usermod -G wheel jesseforrest
Test SSH Connectivity
You should now have SSH access to the new server and be able to “su -” into the root user. To test, open a new terminal window and run the following commands:
# ssh jesseforrest@<new_server_ip_address>
# su -
Enter in the root password.
Disable root SSH Access and Change Default SSH Port Number
The root account should never be able to login via SSH. The user should have to first login as a specific user and then “su -” into root. We should also change the default port used for SSH connectivity to prevent from common attacks. We will switch the SSH port to 11985, but you can pick any open port you like.
Run the following command:
# vi /etc/ssh/sshd_config
Then change the following lines to match the following and then save it:
PermitRootLogin no
Protocol 2
Port 11985
Allow SSH Keys to Connect
You will want to use SSH keys to connect to your server instead of entering in a password.
Open a new terminal window and run the following command:
# ssh-keygen -t rsa -b 2048
Enter in a path to store your *_id_rsa file. The path should be similar to this:
~/.ssh/jesseforrest_id_rsa
Create a new passphrase.
Tip: Store this passphrase in your PasswordSafe.
On the client machine (the computer you will be connecting from) tighten up file system permissions:
# chmod 700 ~/.ssh
# chmod 600 ~/.ssh/*
Now copy the public key to the machine you want to SSH into and fix permissions:
# scp ~/.ssh/jesseforrest_id_rsa.pub jesseforrest@<ip_address_of_server>:
Connect to the remote server:
# ssh jesseforrest@<ip_address_of_server> -p 11985
You will need to create the ~/.ssh directory if it does not yet exist
# mkdir ~/.ssh
Append your public key to the authorized_keys file.
# cat ~/jesseforrest_id_rsa.pub >> ~/.ssh/authorized_keys
Remove the public key file from the server
# rm ~/jesseforrest_id_rsa.pub
Set the permissions so it is only readable and writable by you, the owner.
# chmod 600 ~/.ssh/authorized_keys
# chmod 700 ~/.ssh
Restart SSH Daemon:
# /etc/init.d/sshd restart
Setup Keychain
Use Keychain, an SSH Agent, so that you don’t need to enter a passphrase every time you connect. Install keychain if it is not installed yet:
# wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el5.rf.x86_64.rpm
# rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt
# rpm -i rpmforge-release-0.5.2-2.el5.rf.*.rpm
# yum install keychain
We need to add keychain to start automatically.
# vi ~/.bash_profile
Add the following line:
eval $(keychain --eval --agents ssh -Q --quiet jesseforrest_id_rsa)
Test SSH Connectivity
You should now have SSH access to the new server through SSH keys:
# ssh jesseforrest@<new_server_ip_address> -p 11985
# su -
Enter in the root password.
Disabling Password Logins (only allow SSH)
# vi /etc/ssh/sshd_config
Modify to the following and then save it:
PasswordAuthentication no
ChallengeResponseAuthentication no
Restart SSH Daemon:
# /etc/init.d/sshd restart
Update Path Variable
# vi ~/.bash_profile
Change the line “PATH=$PATH:$HOME/bin” to:
PATH=$PATH:/usr/sbin/:/sbin:$HOME/bin
Optional – Update Hosts File
If this server is not in the Domain Name System (DNS), you must explicitly add it to the /etc/hosts file so that you can reference it by host name.
If necessary, edit /etc/hosts by running the following command:
# vi /etc/hosts
Paste the IP address and host name of the server like this:
<ip_address> <host_name>
Example:
173.232.244.226 mywebsite.com
Setup Hostnames
Make sure the following is set in /etc/sysconfig/network with hostnames changed to the actual host name.
NETWORKING=yes
HOSTNAME=<host_name>
Example:
NETWORKING=yes
HOSTNAME=mywebsite
Start Cron Daemon
# /sbin/service crond start
Disabling SELinux
# vim /etc/selinux/config
Verify it is set to the following:
SELINUX=disabled
Configure the Required System Services to Start at Boot
# chkconfig httpd on
# chkconfig mysqld on
# chkconfig vsftpd on
# chkconfig sshd on
# chkconfig crond on
# chkconfig iptables on
Configure Apache
# vim /etc/httpd/conf/httpd.conf
Fill out the following information (replace <hostname> with something like mywebsite.com):
ServerAdmin support@mywebsite.com
ServerName <hostname>:80
NameVirtualHost *:80
DirectoryIndex index.php index.html index.htm
ServerTokens Prod
ServerSignature Off
Make this change wherever needed:
Options -Indexes FollowSymLinks
Add the following line if it does not exist:
TraceEnable Off
Save the file.
# vim /etc/httpd/conf.d/ssl.conf
Update the SSLCipherSuite line and change +LOW to !LOW
Save the file.
Restart HTTP Daemon
# /etc/init.d/httpd restart
Configure VSFTP
# vim /etc/vsftpd/vsftpd.conf
Make the following changes:
anonymous_enable=NO
xferlog_file=/var/log/vsftpd.log
idle_session_timeout=600
nopriv_user=nobody
ascii_upload_enable=YES
ftpd_banner= **** WARNING - Your actions are being logged ****
pam_service_name=vsftpd
userlist_enable=YES
listen=YES
tcp_wrappers=YES
chroot_local_user=YES
userlist_deny=NO
Next, we need to configure vsftpd.userlist and specify which users can FTP to the server. This compliments the userlist_deny setting in vsftpd.conf. When set to NO, this makes the vsftpd.userlist file a list of users that ARE allowed to log in.
# vim /etc/vsftpd/user_list
We recommend removing all users so that nobody is able to FTP in. However, if you want to allow a user to FTP in, you can add them here.
Configure MySQL
# cd /usr/share/doc/mysql-server-
(hit tab to get current version installed and then hit enter)
# cp my-medium.cnf /etc/my.cnf
(hit enter and then “y” to confirm)
# vim /etc/my.cnf
Paste the following and save. You might want to tweak these values based on your system specifications and database requirements:
[mysqld]
set-variable = max_connections=500
log-slow-queries
safe-show-database
query-cache-type = 1
query-cache-size = 150M
table_cache = 512
thread_cache_size=32
key_buffer_size=128M
long_query_time=2
log_queries_not_using_indexes
Note: This configuration will setup a query cache, log queries that take longer than 2 seconds to run, and log queries that are not using indexes. If you want to change any of this behavior you will need to make the appropriate changes to fit your needs.
Restart MySQL Daemon:
# /etc/init.d/mysqld restart
Now the root password for MySQL must be set using the following command. Do NOT use the same root password as the Linux root password.
# mysqladmin -u root password "<password>"
Tip: Make sure to save the username and password in your PasswordSafe.
Optional – Install and Configure Memcached
Install the memcache daemon:
# yum install memcached
Start the daemon:
# /etc/init.d/memcached start
Even though memcached is running on the server, it’s not accessible from PHP without the PECL extension. So run this:
# pecl install memcache
(Use all defaults)
# vim /etc/php.ini
Paste the following at the bottom of the file:
[memcache]
extension=memcache.so
# vim /etc/sysconfig/memcached
Make the following changes:
PORT="11986"
CACHESIZE="1024"
Restart Apache
# /etc/init.d/httpd restart
Make the service startup on reboot
# chkconfig memcached on
Start Memcache
# /etc/init.d/memcached start
Optional – Install a GoDaddy Signed SSL Certificate
Generate private key:
# openssl genrsa -out ca.key 2048
Copy the necessary key to the required location
# cp ca.key /etc/pki/tls/private/<hostname>.key
Generate CSR:
# openssl req -new -key ca.key -out ca.csr
Enter in all required information.
Get the contents of the CSR by running:
# cat ca.csr
Copy all the contents into “Enter your Certificate Signing Request (CSR) below:” in GoDaddy. Download bundle from GoDaddy and copy those files to the correct locations:
# cp <hostname>.crt /etc/pki/tls/certs/<hostname>.crt
# cp gd_bundle.crt /etc/pki/tls/certs/<hostname>-chain.crt
Update the Apache SSL configuration file:
# vim +/SSLCertificateFile /etc/httpd/conf.d/ssl.conf
Change the paths to match where the Key file is stored:
SSLCertificateFile /etc/pki/tls/certs/<hostname>.crt
Change the path for the Certificate Key File:
SSLCertificateKeyFile /etc/pki/tls/private/<hostname>.key
Change the path to the intermediate bundle file:
SSLCertificateChainFile /etc/pki/tls/certs/<hostname>-chain.crt
Save and close
Restart HTTP Daemon
# /etc/init.d/httpd restart
Optional – Install a Self-Signed SSL Certificate
If you want to install a self-signed SSL certificate, you can follow these steps.
Generate private key:
# openssl genrsa -out ca.key 1024
Generate CSR:
# openssl req -new -key ca.key -out ca.csr
Enter in all required information
Generate self-signed key:
# openssl x509 -req -days 1825 -in ca.csr -signkey ca.key -out ca.crt
Copy the files to the correct locations (do not move them if you use SELinux):
# cp ca.crt /etc/pki/tls/certs
# cp ca.key /etc/pki/tls/private/ca.key
# cp ca.csr /etc/pki/tls/private/ca.csr
Update the Apache SSL configuration file:
# vi +/SSLCertificateFile /etc/httpd/conf.d/ssl.conf
Change the paths to match where the Key file is stored:
SSLCertificateFile /etc/pki/tls/certs/ca.crt
Change the path for the Certificate Key File:
SSLCertificateKeyFile /etc/pki/tls/private/ca.key
Save and close
Restart HTTP Daemon
# /etc/init.d/httpd restart
Optional – Example Configuring Iptables
This will configure Iptables to open the following input ports: 80 (HTTP), 443 (HTTPS), 11985 (SSH). It will also open the following output ports: 80 (HTTP), 443 (HTTPS).
# /sbin/iptables -P INPUT ACCEPT
# /sbin/iptables -F
# /sbin/iptables -A INPUT -i lo -j ACCEPT
# /sbin/iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
Drop packets where new incoming tcp connections are not SYN
# /sbin/iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
Drop packets with incoming fragments
# /sbin/iptables -A INPUT -f -j DROP
Drop incoming malformed XMAS packets
# /sbin/iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
Drop incoming malformed NULL packets
# /sbin/iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
# /sbin/iptables -A INPUT -p tcp --dport 11985 -j ACCEPT
# /sbin/iptables -A INPUT -i eth0 -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
# /sbin/iptables -A OUTPUT -o eth0 -p tcp -m multiport --sports 80,443 -m state --state ESTABLISHED -j ACCEPT
# /sbin/iptables -P INPUT DROP
# /sbin/iptables -P FORWARD DROP
# /sbin/iptables -P OUTPUT ACCEPT
Verify and Save Iptables
Some ports might appear in the nmap output even if you specified them restricted in iptables. This is probably because they are being run from localhost. To verify your iptables configuration you can run:
# /sbin/iptables -L
Run the following if correctly configured:
# /sbin/service iptables save
Verify only the ports you want opened are listed by running the following
# nmap -sT -O localhost
Update PHP Configuration
# vim /etc/php.ini
Make these changes:
display_errors = Off
date.timezone = America/New_York
html_errors = Off
expose_php = Off
error_log = /var/log/php_errors.log
Tip: Set date.timezone to whatever is applicable to your server. A list of timezones are available on PHP’s List of Supported Timezones web page.
Save and quit.
Optional – Install GeoIP
# yum -y install GeoIP GeoIP-devel
# pecl install geoip
# vim /etc/php.ini
Add this to end of php.ini:
[geoip]
extension=geoip.so
Save and quit.
Protect Files and Folders
Set the correct restrictions:
# chown -R apache:apache /var/www/html/
Write protect Apache, PHP, and MySQL configuration files:
# chattr +i /etc/php.ini
# chattr +i /etc/php.d/*
# chattr +i /etc/my.cnf
# chattr +i /etc/httpd/conf/httpd.conf
Restart HTTP Daemon
# /etc/init.d/httpd restart
Verifying Configuration Works
# vim /var/www/html/info.php
Enter:
<?php phpinfo();
Save and quit.
Use browser to hit:
http://<Server_IP_Address>/info.php
Optional – Install locate and updatedb on CentOS
# yum install mlocate
# /etc/cron.daily/mlocate.cron
References
http://www.rayheffer.com/36/building-a-secure-web-server-with-centos-5-part-1/
https://wiki.archlinux.org/index.php/SSH_Keys
This function converts strings into a format that can be used in URLs. For example, the string “Mike’s Karate School” would be returned as “mikes-karate-school”. This function is recommended to be used on non-multibyte character sets. So this is not recommended for UTF-8, since certain PHP functions (like strtolower) should not be used on multibyte strings.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * Returns a string in a URL friendly format. * @param string $str The input string. * @return string The URL friendly string. */ public static function getUrlFriendlyString($str) { // convert spaces to '-', remove characters that are not alphanumeric // or a '-', combine multiple dashes (i.e., '---') into one dash '-'. $str = ereg_replace("[-]+", "-", ereg_replace("[^a-z0-9-]", "", strtolower( str_replace(" ", "-", $str) ) ) ); return $str; } |
In 2011, Joimo took a big leap and started offering a variety of different sports and recreational activities. I’m happy to say that we now offer bowling, dodgeball, indoor soccer, outdoor soccer, and kickball!
Photo from San Diego Co-ed Dodgeball!
In October of 2004, I decided to take on a new project at college. I was determined to write software that could be used in the Computer Science Major’s Lab to monitor who came in and out. I originally began the project in an attempt to learn how to write software that could interpret the data that was received from a card-scanner via a COM port. Then my interest grew and I decided to write a fully functional Log Manager. I knew a variety of other labs wanted a way to log who was coming in and out of their lab, so I figured it was a good project to take on.

Download Log Manager Version 1.3:
Installer | VB 6 Source Code
Log Files:
A new log file is created each day. Log Manager writes the log information to text files in the specified Log Destination. It’s capable of saving the log files to a certain folder on a server if necessary. By default Log Destination is set to “C:\INSTALL_PATH\LogDestination\”. Here is an example of the automatic file creation:
Below is an example of the contents of a log file. It is a comma delimited file, so it can easily be opened in Excel or similar program.

Before Joimo.com came to be, here were a couple of my other concepts..
The function below takes in a string of text and converts all URL’s that start with "http://" to an HTML link.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /** * Returns the string with URL's replaced with actual HTML link tags * @param string $string The string to parse for URL's * @param boolean $noFollow Whether or not to add the rel="nofollow" * attribute to the tag * @param boolean $newWindow Whether or not to make the link open in a new * window * @return string */ function getStringWithUrlLinks($string, $noFollow = true, $newWindow = true) { $pattern = '/(http:\/\/[^\s]+)/'; return preg_replace_callback($pattern, create_function('$matches', 'return \'<a href="\'.$matches[0].\'" ' . (($noFollow) ? ' rel="nofollow"' : '') . (($newWindow) ? ' target="_blank"' : '') . '>\'.$matches[0].\'</a>\';' ), $string); } |
Here is an example usage:
21 22 23 | $string = 'This is my website: http://jesseforrest.name/'; $stringHtml = nl2br(getStringWithUrlLinks(htmlentities($string))); echo $stringHtml; |
The example above would output:
This is my website: http://jesseforrest.name/









