Creating a development Virtual Machine – Part one: Ubuntu, Apache, MySQL, PHP
If you do web development on Windows, you’re probably used to making do. XAMPP can go a long way, as can Cygwin, but once you want to start playing around with anything state-of-the-art, you’ll start feeling left behind. The solution? Set up a virtual machine running Linux, so you can take advantage of the latest and greatest in their native environments.
Set up Ubuntu
For this purpose, we’re going to be using VirtualBox – originally by Sun, recently(ish) purchased by Oracle. For my money, it still has the best mix of ease-of-use, features, and price (free). You can download the latest version here.
And while you’re at it, go download the latest version of Ubuntu Server. For this article, we’re using 11.10 (Oneiric Ocelot), which you can download here. Grab the 64-bit version.
Install VirtualBox. Before you run it the first time, you’ll want to right-click the icon and choose “Properties”. Then go to the “Compatability” tab and click the checkbox next to “Run this program as an administrator”. If you want any symlinks you create in Ubuntu to be recognized by Windows, you MUST be running the program as an administrator. Windows is funny like that.
Launch VirtualBox, then create a new virtual machine and set the Ubuntu ISO as the CD/DVD drive. (Under the Storage menu in Settings, click on the CD-looking thing under the IDE controller). Also, make sure to set up Networking as “Bridged”. Start up the virtual machine, then follow Ubuntu’s really slick install process. The only application you’ll want to install during setup is the OpenSSH server. We’ll install the rest ourselves.
When all is said and done, restart it and log in. Now the fun begins!
Set up your networking
Let’s set up a static IP address so we don’t have to keep figuring out what dynamic IP the machine obtained.
$ sudo nano /etc/network/interfaces
Edit the last part to look like this:
# The primary network interface auto eth0 iface eth0 inet static address 192.168.0.151 netmask 255.255.255.0 network 192.168.0.0 broadcast 192.168.0.255 gateway 192.168.0.1
You’ll have to fiddle with those numbers a bit depending on your networking configuration. Ensure primarily that the address you supply isn’t taken by anyone else on your network, and that the gateway matches the one you get when you type “ipconfig” in Windows. Restart your network to get the changes recognized.
$ sudo /etc/init.d/networking restart
Once that’s working, start up Notepad as Administrator in Windows (right-click and “Run as administrator”). Then open up “C:\Windows\System32\drivers\etc\hosts” (no extension) and add your new machine’s IP address. Now you can do things like SSH directly to the hostname or type the hostname in your browser instead of remembering the IP address.
Install Apache
This is easy, and can be handled entirely through automated utilities built-in to Ubuntu.
$ sudo apt-get install --reinstall language-pack-en $ sudo dpkg-reconfigure locales $ sudo apt-get install gcc make wget cron curl $ sudo apt-get install apache2 apache2-mpm-prefork apache2-prefork-dev apache2-utils apache2.2-common
One quick thing, to avoid getting the error “Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1 for ServerName” every time we restart, we need to make a small change.
$ sudo nano /etc/apache2/httpd.conf
Add the following line and save.
ServerName localhost
Install MySQL
Nearly as easy. Start with the automated utilities.
$ sudo apt-get install mysql-server-5.1
No need to give MySQL a root password on your development box. Then edit the MySQL config file.
$ sudo nano /etc/mysql/my.cnf
Change the “bind-address” line in that file to point the the local server IP. (192.168.0.151 in the example above.)
Then, it’s worthwhile allowing root to log in from machines other than localhost. That way you can use whatever Windows GUI tool you like to log in to your virtual machine’s MySQL installation.
$ mysql -u root GRANT ALL ON *.* TO 'root'@'%'; exit; $ sudo service mysql restart
Install PHP
Now we could just use the built-in version of PHP, if we felt like taking the easy road. But that’s no fun. Let’s install PHP 5.4 RC2, so we can play around with all the new features. As an added bonus, if you get comfortable with compiling PHP now, you can recompile with whatever version and options you want later for when there’s a new release of PHP, and you don’t have to wait for your package maintainers to update.
First we need a bunch of build tools.
$ sudo apt-get build-dep php5 $ sudo apt-get install libxml2 libxml2-dev libzip-dev libbz2-dev curl libcurl4-openssl-dev libcurl3 libcurl3-gnutls libjpeg62 libjpeg62-dev libpng12-0 libpng12-dev libmcrypt-dev libmcrypt4 libxslt1-dev libxml2-dev
Next, grab and extract PHP 5.4.
$ cd ~/ $ mkdir tmp $ cd tmp $ wget http://downloads.php.net/stas/php-5.4.0RC2.tar.gz -O php-5.4.0RC2.tar.gz $ tar xvfz php-5.4.0RC2.tar.gz
Now, we configure and compile. This takes a while. Feel free to grab a sandwich or something.
$ cd php-5.4.0RC2 $ ./configure --with-apxs2=/usr/bin/apxs2 --with-config-file-path=/etc/php5 --with-mysql=mysqlnd --enable-inline-optimization --disable-debug --enable-bcmath --enable-calendar --enable-ctype --enable-force-cgi-redirect --enable-ftp --with-gd --enable-memory-limit --disable-sigchild --enable-trans-sid --with-ftp --with-jpeg-dir=/usr --with-png-dir=/usr --with-zlib=yes --with-zlib-dir=/usr --with-openssl --with-xsl=/usr --with-gd --with-mcrypt=/usr --with-mhash=/usr --enable-mbstring=all --with-curl=/usr/bin --with-curlwrappers --enable-mbregex --enable-zend-multibyte --with-bz2=/usr --with-mime-magic --with-iconv --with-pdo-mysql=mysqlnd --enable-fileinfo --with-pear --enable-exif $ make $ sudo make -i install
Of course, now we have to ensure that Apache knows about PHP.
$ sudo ln -s /usr/local/bin/php /usr/bin/php $ sudo nano /etc/apache2/mods-available/php5.conf
Add the following lines and save.
AddType application/x-httpd-php .php .phtml .php3 AddType application/x-httpd-php-source .phps
Now enable PHP (and mod-rewrite, while we’re at it).
$ sudo a2enmod php5 $ sudo a2enmod rewrite
It wouldn’t hurt to ensure that PHP is configured how we like it, either.
$ cd /etc $ sudo mkdir php5 $ cd php5 $ sudo cp ~/tmp/php-5.4.0RC2/php.ini-production php.ini $ sudo nano php.ini
Ensure the following are set:
date.timezone = America/Toronto (Or whatever is closest to you.) short_open_tag = On error_reporting = E_ALL display_errors = On log_errors = On error_log = /var/log/php.log max_execution_time = 30 memory_limit = 128M mysql.default_socket = /var/run/mysqld/mysqld.sock
Now make sure that the logfile we specified exists and is writable.
$ sudo touch /var/log/php.log $ sudo chmod a+rw /var/log/php.log
Finally, restart Apache!
$ sudo service apache2 restart
You should be able to visit the address of your new virtual machine (or the alias you set up in hosts) now and get your basic Apache display.
Extra step – VirtualHosts
I presume you’re going to want to develop multiple projects without having to create separate virtual machines for them all. That’s easy! We’ll just set up an Apache VirtualHost for each one.
$ sudo nano /etc/apache2/sites-available/{development url}
Add the following, then save.
<VirtualHost *:80> ServerName {development url} DocumentRoot /home/{user}{/{development url}/ <Directory /home/{user}/{development url}/> AllowOverride All </Directory> </VirtualHost>
Now enable your site and reload Apache.
$ sudo a2ensite {development url} $ sudo service apache2 reload
Extra step – Shared folders
I bet you’re wondering how you’re supposed to get files on and off that machine, huh? Well, since you installed OpenSSH, you have options there, but there’s an easier way. You can just share that folder you were referencing above with a specific folder on your host machine. Make changes in Windows, and it will (usually) be reflected in the virtual machine. I’ve noticed a few times that when I’ve created a file, the Ubuntu host flips out and doesn’t properly recognize it, but a quick restart fixes it, and machine restarts are usually like ten seconds, max.
First, make sure that folder above exists on your virtual machine, then click on the “Devices” menu in VirtualBox, then click “Install Guest Additions”. This makes a virtual CD available to your virtual machine that contains the actual guest additions we’re going to install.
$ sudo mount /dev/cdrom /media/cdrom $ cd /media/cdrom $ sudo ./VBoxLinuxAdditions.run
Ignore the crap about x.org failing – we don’t have any GUI installed on the server, so whatever. Now shut down the machine (“sudo shutdown -h now”), and open up the Settings menu and click on Shared Folders. Click the little Folder/Plus icon on the right, and choose a Folder Path from your Windows box, and remember the Folder Name it gives you (or make up your own). Hit “OK” and start that machine back up.
We’re going to set up this machine to automatically mount that folder every time it boots up.
$ sudo nano /etc/init.d/rc.local
Add the following just after “do_start() {“:
mount -t vboxsf {Folder Name} /home/{user}/{development url}
Now restart to check it out.
$ sudo restart -r now # After restarting... $ cd /home/{user}/{development url} $ ls
You should see all the files from your Windows machine. If you don’t, well… ugh. Okay, I got this fixed by re-running the VBoxLinuxAdditions.run script, the re-mounting. No clue why that worked, but it worked, so… yeah. Not questioning it.
What Else Could We Possibly Do?
Hot damn, that’s a lot of stuff, isn’t it? Well, we still have Memcache, Memcached (yes, both), and Redis to install. These are all optional, but super-neat tools, and practically essential if you want to write anything that scales well these days.
For now though, you should have a good base to work from. If anything doesn’t work, let me know, but I followed along with my own VM while I was writing this, so I’m pretty confident I didn’t skip anything.
Comments
T. T. Smyouf
AuthorVery good article.
I will set up my development virtual machine today!
GT Gaastra
AuthorThis article was really helpful, using this style of a development server really helps in my workflow :-).
I’ve got a small addition to the Shared Folder-section. The problem with files not updating properly seems due to apache2 behavior to not read static files itself but letting the OS do this. Somehow this breaks with Virtualbox. ( http://abitwiser.wordpress.com/2011/02/24/virtualbox-hates-sendfile/ ). I mostly ran into this when I updated an image file and had to restart the VM to see the difference.
Changing this setting is luckily easy:
– Open the virtualhost file in /etc/apache2/sites-available/.
– Add “EnableSendfile Off” before one of the sections.
– restart apache.
– Enjoy :-)
– Don’t forget to hit ctrl+f5 to force re-download the images in your browser ;-).
Dan Hulton
AuthorGood catch!
The strange thing is, I just switched back to this style of development recently, and a co-worker of mine encountered and found the fix to that same problem yesterday!
Timing!