
I’ve bought a new VPS Server in the past for hosting some of my sites, setting up new VPS is not easy as you think, but if you need tutorial step by steps for help on setting up a VPS or dedicated server, so I thought I would go ahead and make a guide on how to set one up from start to finish to cover all of the bases. That being said, I obviously can’t go into detail on how to get things up and running for every possible setup, operating system, or distribution. Here is a list of assumptions/requirements I am making for this guide:
- You are running Ubuntu >= 10.10 (Maverick), although any Debian Linux distribution is probably fine
- You have at least some basic command-line knowledge (mostly meaning you’ve used SSH before and know how to edit files in the Terminal)
- You want to use Nginx as a web server and not Apache (trust me, you won’t regret it)
- You know DNS well enough to get that side of things setup. This guide is going to stick to installing and configuring software.
- You are running these commands as root. If that scares you, then make sure you put “sudo” in front of the apt-get commands and the ‘make install’ command.
- Oh and just to be clear, if there is a # in front of a Terminal line, that is just the bash prompt. Don’t enter it with the command after it.
So, assuming you have a fresh server ready to go (sorry, not going to cover OS install as that’s pretty trivial), let’s go!
Preliminary Steps
First, there are a few things that we need to do because they will become useful or needed later in the setup process. They’re pretty basic, but they are easy to forget.
# apt-get update # apt-get upgrade # apt-get install build-essential
Installing PHP
Now that that’s out of the way, the first thing we’re going to need to do is to install PHP. Luckily, Ubuntu keeps the version in the repository up to date (unlike CentOS) so this is very simple to do. If you are using Ubuntu 10.10 (Maverick), then you will get the benefit of PHP 5.3.5. Otherwise, you will get PHP 5.3.2.
# apt-get install php5-cli php5-cgi php5-dev php-pear php5-xcache php5-mysql php5-mcrypt
You may notice that we didn’t install the base php5 package. This is because this package is intended for Apache web servers, and thus we will not need it. You may also have noticed that we installed XCache. This is optional, but I recommend it as it will help speed things up.
Double-checking to make sure everything installed ok, we can run:
# php -v PHP 5.3.2-1ubuntu4.5 with Suhosin-Patch (cli) (built: Sep 17 2010 13:49:46) Copyright (c) 1997-2009 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies with XCache v1.3.0, Copyright (c) 2005-2009, by mOo
Installing MySQL
Next up we need to install MySQL. Luckily this is also very straightforward:
# apt-get install mysql-server mysql-client
This will install MySQL and all of its dependencies. You will be prompted to enter and confirm a new password for the root MySQL user, so make sure you don’t forget it! To test that MySQL is up and running, run:
# mysql -uroot -p
and enter the root password you just specified during the install at the prompt. You should be presented with something along the lines of:
# mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; or g. Your MySQL connection id is 39 Server version: 5.1.41-3ubuntu12.6 (Ubuntu) Type 'help;' or 'h' for help. Type 'c' to clear the current input statement. mysql>
This means your MySQL server is up and running! If you are unable to connect, try running:
# service mysql start
Installing Nginx
Now it’s time to install our web server: Nginx. I won’t go into detail about how cool Nginx is in this guide, but if you’re unfamiliar with it: it’s pretty damn cool.
Up until now, we’ve been cruising through software installation. Unfortunately, the version of Nginx in the Ubuntu repository is very out of date. At the time of this writing, the version in the repository is 0.9.5 while the latest stable version is 0.9.7.
However, never fear! Nginx provides their own repository for the latest stable versions for Ubuntu. To add this repository, run:
# echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu lucid main" >> /etc/apt/sources.list # apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C # apt-get update
Now that we have access to the Nginx repository, we can run:
# apt-get install nginx
To verify Nginx is installed and working:
# nginx -v # nginx version: nginx/0.9.7
Configuring Nginx
Now, this guide gets a little trickier and a little bit rougher in this section. Website organization and folder structure is often a matter of personal preference. Keep in mind there is no right or wrong way of organizing your website folders (ok well, maybe putting your site in /root isn’t a good idea but you get the gist of it), so feel free to change the paths around. What follows is how I set up my own server.
The main Nginx configuration is in /etc/nginx/nginx.conf, so let’s make a few tweaks to that first:
user www-data; worker_processes 4; error_log /var/log/nginx/error.log; pid /var/run/nginx.pid; events { worker_connections 1024; # multi_accept on; } http { include /etc/nginx/mime.types; access_log /var/log/nginx/access.log; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 2; tcp_nodelay on; gzip on; gzip_disable msie6; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }
The main thing we changed was increasing worker_processes from 1 to 4, but I thought I would paste the file in its entirety just in case. If you look closely, you’ll see that Nginx includes all files in /etc/nginx/sites-enabled/, so let’s take advantage of this to improve our configuration file organization.
Create a file with a descriptive name, one for each of your domains (not subdomains, unless you really want to), and put it in something along the lines of:
server { listen 80; ## listen for ipv4 server_name meltingice.net; ## change this to your own domain name # I find it really useful for each domain & subdomain to have # its own error and access log error_log /var/log/nginx/meltingice.net.error.log; access_log /var/log/nginx/meltingice.net.access.log; location / { # Change this to the folder where you want to store your website root /home/meltingice_net/public_html; index index.html index.htm index.php; } # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www/nginx-default; } # We haven't setup FastCGI yet, but lets configure this now anyways # # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 location ~ .php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; # again, change the directory here to your website's root directory # make sure to leave $fastcgi_script_name; on the end! fastcgi_param SCRIPT_FILENAME /home/meltingice_net/public_html$fastcgi_script_name; include /etc/nginx/fastcgi_params; } }
Repeat this server block for every subdomain you wish to use, replacing the domain with the subdomain. Don’t bother restarting Nginx at this point in time because it will fail due to the fastcgi_params file missing. That comes next!
Configuring and Running FastCGI
There are many different ways to work with FastCGI, but we’re going to do what should be the easiest. Remember the php5-cgi that we installed earlier? It has a built-in spawning system that will start up our php-cgi instances for us and listen for connections. First, though, we need to create a simple file that defines all of the FastCGI params for us. Create the file /etc/nginx/fastcgi_params and paste into it:
fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200;
Now what we need to do is create an init.d script that will make starting and stopping these php-cgi instances much easier. Create the file /etc/init.d/php-fastcgi and open it for editing and copy and paste into it:
#!/bin/bash RETVAL=0 export PHP_FCGI_MAX_REQUESTS=20 export PHP_FCGI_CH BIND=127.0.0.1:9000 USER=www-data PHP_FCGI_CHILDREN=5 PHP_CGI=/usr/bin/php5-cgi PHP_CGI_NAME=`basename $PHP_CGI` PHP_CGI_ARGS="- USER=$USER PATH=/usr/bin PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS $PHP_CGI -b $BIND" case "$1" in start) echo "Starting PHP FastCGI..." start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS RETVAL=$? echo "$PHP_CGI_NAME." ;; stop) killall -9 php5-cgi RETVAL=$? ;; restart) killall -9 php5-cgi start-stop-daemon --quiet --start --background --chuid "$USER" --exec /usr/bin/env -- $PHP_CGI_ARGS RETVAL=$? ;; *) echo "Usage: php-fastcgi {start|stop|restart}" exit 1 ;; esac exit $RETVAL
There are a lot of options to configure in this file, but their values depend on the power and size of your server. If you have a small VPS, for instance, you want PHP_FCGI_MAX_REQUESTS and PHP_FCGI_CHILDREN to be small in order to prevent your RAM from filling up and enabling disk swap. Play with these values until you find a sweet spot. The values included in the file above are intended for a small VPS.
Now we can run:
1 chmod +x /etc/init.d/php-fastcgi 2 /etc/init.d/php-fastcgi start 3 4 update-rc.d php-fastcgi defaults
which will start our php-cgi instances. The last command will make sure that the php-cgi instances are started at boot time as well, in case you ever need to reboot the server.
Nginx and PHP Testing
Now that all of the basic pieces are done for setting up a web server, you can check to see if it’s working properly or not. Make sure the root directory for your website that you specified in the Nginx config file is created and put an index.php file in that directory. Put some simple code in this file for testing… something along the lines of:
1 <? echo "test"; ?>
If you set up your DNS and domain name ahead of time, try visiting your domain. If not, you should be able to go directly to your server’s IP address and see it because Nginx defaults to the last server block that was defined (if I remember correctly).
Additional (Optional) Setup Steps
From here on, all of these steps are optional. All of the steps described here are things that I have installed/used in the past, so I thought I would include them in this guide.
Configuring XCache
Since we have XCache running, let’s take a moment to configure it instead of relying on its defaults. We will also set up the XCache admin pages in this section.
Since we will want to password protect the XCache admin pages, we will need to get the md5 hash of your preferred password. You can do it on a site like MD5 Encrypter, or you can run a quick PHP script do to it for you. Either works. Once you get the MD5 hash of your password, hold on to it because we’ll need it for the configuration.
In your php.ini file, which should be located in /etc/php5/cgi/php.ini, check to see if any XCache settings are listed. If not, add this to the end of the file but replace xcache.admin.user and xcache.admin.pass with your desired username and MD5 password hash:
; XCACHE SETTINGS [xcache-common] extension = xcache.so [xcache.admin] xcache.admin.user = "your_username" ; xcache.admin.pass = md5($your_password) xcache.admin.pass = "md5 hash of your password" [xcache] ; ini only settings, all the values here is default unless explained ; select low level shm/allocator scheme implemenation xcache.shm_scheme = "mmap" ; to disable: xcache.size=0 ; to enable : xcache.size=64M etc (any size > 0) and your system mmap allows xcache.size = 48M ; set to cpu count (cat /proc/cpuinfo |grep -c processor) xcache.count = 1 ; just a hash hints, you can always store count(items) > slots xcache.slots = 8K ; ttl of the cache item, 0=forever xcache.ttl = 0 ; interval of gc scanning expired items, 0=no scan, other values is in seconds xcache.gc_interval = 0 ; same as aboves but for variable cache xcache.var_size = 48M xcache.var_count = 1 xcache.var_slots = 8K ; default ttl xcache.var_ttl = 0 xcache.var_maxttl = 0 xcache.var_gc_interval = 300 xcache.test = Off ; N/A for /dev/zero xcache.readonly_protection = Off ; for *nix, xcache.mmap_path is a file path, not directory. ; Use something like "/tmp/xcache" if you want to turn on ReadonlyProtection ; 2 group of php won't share the same /tmp/xcache ; for win32, xcache.mmap_path=anonymous map name, not file path xcache.mmap_path = "/dev/zero" ; leave it blank(disabled) or "/tmp/phpcore/" ; make sure it's writable by php (without checking open_basedir) xcache.coredump_directory = "" ; per request settings xcache.cacher = On xcache.stat = On xcache.optimizer = On [xcache.coverager] ; per request settings ; enable coverage data collecting for xcache.coveragedump_directory and xcache_coverager_start/stop/get/clean() functions (will hurt executing performance) xcache.coverager = Off ; ini only settings ; make sure it's readable (care open_basedir) by coverage viewer script ; requires xcache.coverager=On xcache.coveragedump_directory = ""
This configuration is, again, for a small VPS. If you have a beefier server, increase the cache size.
Now, to enable the admin pages, we need to make a symbolic link. Go to the folder in your webroot where you want to host the XCache pages from. Personally, I went to /home/meltingice_net/public_html/ which is my root web directory. Once you’re there, run:
1 ln -s /usr/share/xcache/admin xcache
This will create a symbolic link to the XCache admin files in a folder named “xcache”. Now if you go to the corresponding URL, such as http://meltingice.net/xcache, you should be asked for your username and password.
Setting up Memcached
Memcached has been a lifesaver for me for a while now. I highly recommend using it if you are running a website that gets a decent amount of traffic, or if you are running WordPress (used in conjunction with W3 Total Cache). Unfortunately, the version in the Lucid Ubuntu repository is very out of date, so we are going to need to compile some code. If you are running Ubuntu 10.10 (Meerkat), you can run:
1 apt-get install memcached
to get the latest stable version. I’m going to cover installation on Lucid for now since Meerkat just came out and Lucid is a long-term release.
First, we need to download, compile, and install libevent. At the time of this writing, the latest stable release is 1.4.14b, but I would check the website and make sure you get the latest version. Libevent shouldn’t have any more dependencies, so let’s go ahead and make this happen:
# wget http://monkey.org/~provos/libevent-1.4.14b-stable.tar.gz # tar xvf libevent-1.4.14b-stable.tar.gz # cd libevent-1.4.14b-stable # ./configure # make # make install
Now that libevent is installed, we can do the same for Memcached. Again, make sure you grab the latest version from the website.
# wget http://memcached.googlecode.com/files/memcached-1.4.5.tar.gz # tar xvf memcached-1.4.5.tar.gz # cd memcached-1.4.5 # ./configure --with-libevent=/usr/local/lib # make # make install
This will compile and install Memcached in /usr/local/bin by default. Unfortunately, you will probably run into this problem when you try to run Memcached:
memcached: error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory
Luckily, the fix is simple although it is not obvious at first and is not trivial unless you really know what you’re doing. First, we need to create /etc/ld.so.conf.d/libevent-i386.conf then open it for editing and paste into it:
1 /usr/local/lib/
Now run:
1 ldconfig
And that should fix it! We had to do this because, when libevent was installed, it didn’t register itself with Linux, so we had to do it manually. Now, to start Memcached as a daemon with a maximum of 128MB of RAM, we run:
1 memcached -u nobody -d -m 128 -l localhost -p 11211
To check to make sure it’s running, you can run:
1 ps aux | grep memcached
and you should see Memcached listed with the command-line arguments you specified when starting it.
Installing Redis
Ubuntu also did a great job of updating Redis for 10.10 (Meerkat), but if your ubuntu machine use version in the Lucid repository is very out of date. If you are running Meerkat, simply do:
1 apt-get install redis-server
If you are running Lucid, then you will need to compile Redis to get the latest version. Luckily, it’s very easy to compile (notice there is no configure step):
1 wget http://redis.googlecode.com/files/redis-2.0.2.tar.gz 2 tar xvf redis-2.0.2.tar.gz 3 cd redis-2.0.2 4 make 5 cp redis-server /usr/local/bin/ 6 cp redis-cli /usr/local/bin/ 7 cp redis.conf /etc/
This will compile Redis and move it into a directory that is in our PATH so that we can run it easily. To make life even easier, let’s create an init.d script to start and stop it. Create the file /etc/init.d/redis-server and open it for editing:
01 #!/bin/bash 02 REDIS_SERVER=/usr/local/bin/redis-server 03 RETVAL=0 04 05 case "$1" in 06 start) 07 echo "Starting Redis Server..." 08 $REDIS_SERVER /etc/redis.conf 09 RETVAL=$? 10 ;; 11 stop) 12 killall -9 redis-server 13 RETVAL=$? 14 ;; 15 restart) 16 killall -9 redis-server 17 $REDIS_SERVER /etc/redis.conf 18 RETVAL=$? 19 ;; 20 *) 21 echo "Usage: redis-server {start|stop|restart}" 22 exit 1 23 ;; 24 esac 25 exit $RETVAL
Now, in order to force Redis to daemonize instead of opening in the foreground and stealing the Terminal, we need to change one small thing in /etc/redis.conf. Look for “daemonize no” and change it to:
1 daemonize yes
Now you should have a fully working Redis server! Feel free to read through the redis.conf file and tweak more settings as you see fit. It’s pretty well documented.
More Guides?
Let’s face it, this blog post is pretty massive so far. I may even consider turning this into its own static page it becomes so big. If you have any more suggestions for guides I should add, or if you notice a mistake in any of my guides, please let me know! I appreciate all feedback!