.

Set Up Unmanaged VPS (4 Newbies) – Part 13: Serve Multiple Sites & Blogs with Virtual Hosts

English   English (change)

Set Up Unmanaged VPS (4 Newbies) – Part 13: Serve Multiple Sites & Blogs with Virtual Hosts

website file structure image

Now to add sites & blogs to our powerful web server, using vhost (virtual host) files and symlinks. We’ll create a site file structure, add users with groups & permissions, tweak Nginx with FastCGI support and upload pages using SFTP.

OK, so we’ve got Nginx humming on our shiny new Linux server, within our spanky new VPS. By the end of this how-to post, we’ll have some sites resolving.

Essentially, we’re going to create a multi-site & blog document tree, on which to hang our webs. Then we’re going to use a simple copy/paste/fill-the-blanks procedure to add more sites whenever we want. In fact, if you fancy setting up your own web host co-op, by the end of this guide you’ll be able to start signing up the neighbours.

[sniplet guvSellBox]
[sniplet vpsIndexSell]
[sniplet video]

Two notes:-

  • In this tutorial I’m using the username ‘guvnr’ and domain examples ‘waywiderweb’ and ‘waywiserweb’. So swap those for your username and domain(s).
  • Also, bear in mind, for sites to resolve, you’ll need a ‘domain zone’ for each, so refer back to Part 9: Add a Domain Zone to Your VPS for how to do that on your unmanaged virtual private server.

Create the Site File Structure

Let’s add the web directory, in which all your webs will reside:-

[text]sudo mkdir /home/public_html[/text]

And, in there, add a standard set of four folders, per domain. I’ll add folders for 2 domains, ‘waywiderweb’ and ‘waywiserweb’. Add as many as you like:-

[text]sudo mkdir -p /home/public_html/waywiderweb.com/{public,private,log,backup}[/text]
[text]sudo mkdir -p /home/public_html/waywiserweb.com/{public,private,log,backup}[/text]

Add Users, Groups & Permissions

Setup users & groups with appropriate ownership permissions:-

[text]
sudo -i
addgroup webmasters
usermod -G webmasters guvnr
[/text]

.. which basically means we’ve assumed SuperUser permissions, added a group & modified the user ‘guvnr’ to add to the new group.

Optionally, add more users, giving them ‘webmasters’ group permissions. You’ll have to add them first. Mine are Jack and Jill:-

[text]
adduser jack
usermod -G webmasters jack
adduser jill
usermod -G webmasters jill
[/text]

Edit the web directory ownership. In my case, I want user ‘guvnr’ & group ‘webmasters’ to own that:-

[text]
chown -R guvnr:webmasters /home/public_html
chmod -R g+w /home/public_html
[/text]

Looking ahead, we set the group id to ‘webmasters’ for newly-created files & folders:-

[text]find /home/public_html -type d -exec chmod g+s {} ;[/text]

And logout of ‘root’ account (which takes you back to your user account in the CLI):-

[text]exit[/text]

Make Homepage(s)

Create a homepage for the first new domain:-

[text]sudo nano /home/public_html/waywiderweb.com/public/index.html[/text]

…pasting some content within:-

[text]

;)

[/text]

…CTRL-X to quit, press ‘y’ to save & hit return.

Optionally, repeat for subsequent domains.

Create the Virtual Host Files & Symlinks

What are vhosts & symlinks?

You have one of each per domain.

The symlink, or symbolic link, references the web server to the virtual host file.

The vhost file is a configuration file. It tells the web server, for example, things like where the web files live or the kind of URI structure you want.

As we did for the default settings in Part 11: Nginx (better than Apache) Web Server, we’ll create a vhost file & a symlink for each domain. First the vhost:-

[text]sudo nano /usr/local/nginx/sites-available/waywiderweb.com[/text]

…paste this within:-

[text]
server {
listen 80;
server_name www.waywiderweb.com;
rewrite ^/(.*) http://waywiderweb.com/$1 permanent;
}

server {
listen 80;
server_name waywiderweb.com;
access_log /home/public_html/waywiderweb.com/log/access.log;
error_log /home/public_html/waywiderweb.com/log/error.log;

location / {
root /home/public_html/waywiderweb.com/public/;
index index.php index.html;
}

# 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;
include /usr/local/nginx/conf/fastcgi_params;
fastcgi_param SCRIPT_FILENAME /home/public_html/waywiderweb.com/public/$fastcgi_script_name;
}
}
[/text]

With that, your URI will appear as http://waywiderweb.com. If you prefer the format http://www.waywiderweb.com, scrap the above and paste this instead:-

[text]
server {
listen 80;
server_name waywiderweb.com;
rewrite ^/(.*) http://www.waywiderweb.com/$1 permanent;
}

server {
listen 80;
server_name www.waywiderweb.com;
access_log /home/public_html/waywiderweb.com/log/access.log;
error_log /home/public_html/waywiderweb.com/log/error.log;

location / {
root /home/public_html/waywiderweb.com/public/;
index index.php index.html;
}
# 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;
include /usr/local/nginx/conf/fastcgi_params;
fastcgi_param SCRIPT_FILENAME /home/public_html/waywiderweb.com/public/$fastcgi_script_name;
}
}
[/text]

Repeat that virtual host file creation, pasting the code within, for any more domains.

Now, for all domains, add the symlink:-

[text]sudo ln -s /usr/local/nginx/sites-available/waywiderweb.com /usr/local/nginx/sites-enabled/waywiderweb.com[/text]

Tweak Nginx for FastCGI Support

This will make Nginx run with PHP on reboot. Thanks to Stoyan for this solution, and to Gleb, for a handy chunk of code.

We need to install the library:-

[text]sudo aptitude -y install libfcgi0ldbl[/text]

Create a file:-

[text]
sudo nano /etc/default/php-fastcgi
[/text]

…and paste the configuration settings:-

[text]
#
# Settings for php-cgi in external FASTCGI Mode
#

# Should php-fastcgi run automatically on startup? (default: no)

START=yes

# Which user runs PHP? (default: www-data)

EXEC_AS_USER=www-data

# Host and TCP port for FASTCGI-Listener (default: localhost:9000)

FCGI_HOST=localhost
FCGI_PORT=9000

# Environment variables, which are processed by PHP

PHP_FCGI_CHILDREN=5
PHP_FCGI_MAX_REQUESTS=1000
[/text]

Now to make FastCGI start on demand. We’ll create another file:-

[text]
sudo nano /etc/init.d/php-fastcgi
[/text]

…and paste this lot within:-

[text]
#!/bin/sh
### BEGIN INIT INFO
# Provides: php-fastcgi
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start and stop php-cgi in external FASTCGI mode
# Description: Start and stop php-cgi in external FASTCGI mode
### END INIT INFO

# Author: Kurt Zankl

# Do NOT “set -e”

PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC=”php-cgi in external FASTCGI mode”
NAME=php-fastcgi
DAEMON=/usr/bin/php-cgi
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
#. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions

# If the daemon is not enabled, give the user a warning and then exit,
# unless we are stopping the daemon
if [ "$START" != "yes" -a "$1" != "stop" ]; then
log_warning_msg “To enable $NAME, edit /etc/default/$NAME and set START=yes”
exit 0
fi

# Process configuration
export PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS
DAEMON_ARGS=”-q -b $FCGI_HOST:$FCGI_PORT”

do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon –start –quiet –pidfile $PIDFILE –exec $DAEMON –test > /dev/null
|| return 1
start-stop-daemon –start –quiet –pidfile $PIDFILE –exec $DAEMON
–background –make-pidfile –chuid $EXEC_AS_USER –startas $DAEMON —
$DAEMON_ARGS
|| return 2
}

do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon –stop –quiet –retry=TERM/30/KILL/5 –pidfile $PIDFILE > /dev/null # –name $DAEMON
RETVAL=”$?”
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon –stop –quiet –oknodo –retry=0/30/KILL/5 –exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don’t delete their pidfiles when they exit.
rm -f $PIDFILE
return “$RETVAL”
}

case “$1″ in
start)
[ "$VERBOSE" != no ] && log_daemon_msg “Starting $DESC” “$NAME”
do_start
case “$?” in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg “Stopping $DESC” “$NAME”
do_stop
case “$?” in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
restart|force-reload)
log_daemon_msg “Restarting $DESC” “$NAME”
do_stop
case “$?” in
0|1)
do_start
case “$?” in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo “Usage: $SCRIPTNAME {start|stop|restart|force-reload}” >&2
exit 3
;;
esac

:
[/text]

That script needs permission to initiate on reboot and some startup hooks:-

[text]
sudo chmod +x /etc/init.d/php-fastcgi
sudo /usr/sbin/update-rc.d -f php-fastcgi defaults
[/text]

Now boot it with this:-

[text]sudo /etc/init.d/php-fastcgi start[/text]

And restart Nginx:-

[text]n2r[/text]

…or if that doesn’t work (you didn’t follow Part 7: Edit bashrc for User-Friendly Linux, huh?), use…

[text]sudo /etc/init.d/nginx restart[/text]

Check your site in a web browser. Then, reboot Linux:-

[text]sudo reboot[/text]

And check again.

Adding your Sites Using SFTP

Refer to Part 12: Setup FileZilla for Secure FTP (SFTP) for how to set up a popular Secure FTP client (with SSH tunnelling for data encryption.)

Within the document structure we set up above, the web files for each site sit in the ‘public’ folder. To be clear, log into an FTP client and head to your equivalent to:-

[text]
/home/public_html/waywiderweb.com/public/ # here’s a website root folder
/home/public_html/waywiserweb.com/public/ # here’s another website root folder
[/text]

You guessed it. You can upload your site & blog files in there, binning the test homepages we created above.

Fine-tuning for WordPress

If you want WordPress, we’ll fine-tune our system for that in Part 14: Set up WordPress on Nginx with Pretty URLs & WP Super Cache. Not only does it perform well, with happy links, but using Subversion makes for a super-swift platform/plugin install, with hyper-fast updates for both thereafter.

OK, tea-time.

Looking Ahead

I’ll wrap up the series with posts about adding a control panel, configuring Google Apps for your domain-specific email, and the moving day POA. Then you can kiss that shared host goodbye!

Missed something? Here’s the series index…

[sniplet vpsIndex]

.