Ubuntu Hardy - Nginx Virtual Hosts

Now we have Nginx installed (whether via the package manager or from source) we are in a position to serve multiple domains using Virtual Hosts.

Do note the layout used in this article is explained here - feel free to use the directories of your choice.

Create the layout

Let's create the basic layout for each domain. In your home directory create a 'public_html' folder:

mkdir /home/demo/public_html

Now for each domain you want to host (I use the examples of domain1.com and domain2.com) create a folder with a standard set of sub-folders:

mkdir -p /home/demo/public_html/domain1.com/{public,private,log,backup}


mkdir -p /home/demo/public_html/domain2.com/{public,private,log,backup}

That will create the folders public, private, log and backup for each of our domains (domain1.com and domain2.com).


The content of the public folder is, naturally, up to you but for this example I am going to use a very simple html file so we can check the virtual hosts work.

So for each domain:

nano /home/demo/public_html/domain1.com/public/index.html

Enter something like this into the file:


Repeat the process so you have a similar file for domain2.com (don't forget to change the index.html content so it shows domain2.com and not domain1.com).

Virtual Hosts Layout

If you have been following the articles for the Nginx install, you will have a 'Debian' style layout (using sites-available and sites-enabled folders) whether you installed via the package manager or via source.

As such, we'll use that layout from now on when creating the virtual hosts.

Virtual Host

Let's go ahead and create the vhost file for domain1:

sudo nano /etc/nginx/sites-available/domain1.com

Remember to adjust the path according to your install. So installing from source would require:

sudo nano /usr/local/nginx/sites-available/domain1.com

The contents look like this:

server {

            listen   80;
            server_name  www.domain1.com;
            rewrite ^/(.*) http://domain1.com/$1 permanent;


server {

            listen   80;
            server_name domain1.com;

            access_log /home/demo/public_html/domain1.com/log/access.log;
            error_log /home/demo/public_html/domain1.com/log/error.log;

            location / {

                        root   /home/demo/public_html/domain1.com/public/;
                        index  index.html;



Note: This example vhost is pretty basic. However, the next article on Nginx virtual hosts will include details of many more settings that are available.

The first server module in the file is a simple rewrite rule that redirects visitors to domain1.com from www.domain1.com.

You can, of course, have this the other way around if you prefer.

The second server module has very basic information including the server_name which is the domain name you want to serve.

It then defines the log locations for easy analysis and finally sets the server root and the index file.

As said, very basic at this stage.


Last configuration we need to do is to 'enable' our site.

This is done with a symlink in the sites-enabled directory as follows:

sudo ln -s /etc/nginx/sites-available/domain1.com /etc/nginx/sites-enabled/domain1.com

Again, depending on how you installed Nginx, you may need to adjust the paths:

sudo ln -s /usr/local/nginx/sites-available/domain1.com /usr/local/nginx/sites-enabled/domain1.com

Restart Nginx

Although there is a restart option for the Nginx init script, it doesn't always work as expected and may not facilitate any changes you have made.

As such, I recommend a stop and start approach rather than a simple restart:

sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx start


Now when you navigate to your domain:


You will see the equivalent of this:

Nginx domain1.com


Rinse and Repeat

All you need to do for your next virtual host (domain2.com in this example) is to repeat the process.

I know I mention it a lot, but do remember to adjust any paths to match your Nginx installation.

So create a virtual host file:

sudo nano /etc/nginx/sites-available/domain2.com

Enter the details as shown above but for domain2.com and then create a symlink in the sites-enabled folder like this:

sudo ln -s /etc/nginx/sites-available/domain2.com /etc/nginx/sites-enabled/domain2.com

Restart Nginx:

sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx start

And away you go.


Remember we defined custom locations for the domain logs?

Well, let's have a check they are there:

ls /home/demo/public_html/domain1.com/log/
access.log  error.log

Excellent, everything is working as we expected and we have our domain logs in a nice and convenient location.


Setting up virtual hosts with Nginx is a simple process using the sites-available and sites-enabled folders.

Although the example here is quite basic, I hope you can see that getting to grips with Nginx syntax and configurations is not too difficult.

The next article will concentrate on some other settings for use in the virtual hosts file, thus allowing for more control and flexibility for your hosting needs.


Article Comments:

Todd commented Wed May 28 18:45:35 UTC 2008:

Could this be modified to support multiple domains from one Rails app:

http://bills_web.com <--> http://railsapp.com/users/bill

Todd commented Fri May 30 00:23:19 UTC 2008:

This worked like a charm.

I needed to get my DNS setup, so this [Creating DNS Records]http://articles.slicehost.com/2007/10/24/creating-dns-recordsarticle might be helpful as well.

BTKO commented Sun Jun 15 18:20:50 UTC 2008:

Hi there!

Great tutorials, I've been working through them and have had an easy time setting up my new slice. Just ran into a snag now though; I get the following error when I restarted NGINX:

Starting nginx: 2008/06/15 18:08:39 [emerg] 4645#0: unknown directive "location/" in /etc/nginx/sites-enabled/domain1.com:17

BTKO commented Sun Jun 15 21:19:28 UTC 2008:

Scratch that, issue solved -

a typo in the vhost file. Thanks again for the great tutorials

Scott Motte commented Wed Aug 20 06:45:49 UTC 2008:

I'd recommend updating the config lines: server_name www.domain1.com; rewrite ^/(.*) http://domain1.com permanent;

to: server_name www.domain1.com; rewrite ^/(.*) http://domain1.com/$1 permanent;

This is something that Apache's defaults seem to already do, and I think is probably better practice. That way when you type in http://www.domain.com/about-us/ you get redirected back to http://domain.com/about-us rather than back to the root http://domain.com.

Great Article! I refer to it often.

PickledOnion commented Thu Sep 18 08:09:58 UTC 2008:


Thanks for the tip - it was something mentioned before but slipped under the radar.

I have changed it to reflect your suggestion.

Always feel free to add suggestions/corrections as I appreciate any improvements!


Ryan commented Thu Sep 18 18:18:45 UTC 2008:


Check http://articles.slicehost.com/2008/5/16/ubuntu-hardy-nginx-virtual-host-settings

As well. It has the same error as your previous comment.

Steve commented Sat Nov 01 14:51:28 UTC 2008:

Another great tutorial. I just started with slicehost and chose it over linode because of these tutorials... I'm very happy I did, this has saved me hours of work.

czep commented Wed Dec 03 20:38:51 UTC 2008:

If you end up with 403 Forbidden errors on your vhosts, check the permissions on your home directory. The default for home directories is 750, meaning only users and groups can read files inside. Note that all sub-directories INHERIT these permissions, so even if /home/demo/public_html/domain1.com/public is set to 755, if nginx is running as user www-data, it will not be able to access any files because of the 750 permissions on /home/demo.

To solve this you could: 1) chmod 755 /home/demo But this opens up your home directory for world readability, which you may not want. 2) Create a /home/public_html and give it a group that both your user name and the user that nginx is running belong to. There are [good instructions here][http://www.mensk.com/webmaster-toolbox/perfect-ubuntu-hardy-nginx-mysql5-php5-wordpress/] 3) Run nginx as you, but again this may not be desirable for security concerns.

I recommend using #2, as it is probably better to keep all website content out of your personal home directory, particularly if you are going to have multiple sites and potentially multiple users.

jmcarter commented Mon Jan 19 23:50:49 UTC 2009:

Are there any issues (e.g. security, performance) of using the approach in the section 'Wildcard Subdomains in a Parent Folder' from the following link:


Nathan commented Mon Mar 30 20:49:48 UTC 2009:

Purple Onion — First, your tutorials have been a lifesaver. Thank you so much for writing these! I have learned a lot.

I ran into a problem with your sites-available settings. Putting root and index under location / was incorrectly pointing $SERVER["DOCUMENTROOT"] to /usr/local/nginx/html.

Moving root and index out of location / to server fixed the issue.

The only question I still have on this is: Is there still any need to define root or index under location /? My sites are working fine without it, but I haven't been able to confirm that I'm doing things the correct way.

gordon commented Wed Jul 15 11:58:47 UTC 2009:

thank you for your tutes! i understand how to set up NgiNx.

I tried to use NgiNx for my phpPgAdmin and Squirrelmail (which are runnign on apaache) but i have not been too successful.

I guess it is because there's not too many good guides on it.

Can you please shed some light there?

For example, i have a domain, www.staplers.com and i just want to access 1) phpPgAdmin via www.staplers.com/phpPgAdmin 2) Squirrelmail via www.staplers.com/mail

thank you

gatavas commented Thu Jul 23 18:03:58 UTC 2009:

good article.

when I call http://localhost/, all errors are logged in "/var/log/nginx/error.log" (setting in nginx.conf)

wehen I call http://domain1.com/, "/home/demo/public_html/domain1.com/log/error.log" is always empty. what may be wrong?

Aaron Newton commented Sat Jul 03 15:42:20 UTC 2010:

Nice. I'm trying to modify this so it will work on my Windows installation with PHP FCGI across all sites, but it seems to be going well so far.

One question though - does anyone know if it's possible to use a database for some configurations? At the moment I am using Apache with VhostDbi. I've seen a few references for NGinX DBI, but nothing concrete.

Christian commented Thu Feb 03 05:45:40 UTC 2011:

Great post PickledOnion! One thing though, I get an error message reading:

Starting nginx: [warn]: duplicate MIME type "text/html" in /etc/nginx/nginx.conf:27

Any thoughts on why this might be happening?

Thanks in advance!

Chua Wen Ching commented Tue Jul 12 07:42:11 UTC 2011:

Hi pickledonion,

one question. Does the demo user can be a normal user or it needs to be any special kind of privileges?

any tips to create user like demo?

Any help? Thanks.

Jered commented Wed Jul 13 13:42:43 UTC 2011:

For the purposes of the web server, "demo" can be any user on the system. The only requirement would be that the nginx process be able to view the files in the user's home directory so it can serve up the virtual host. You can create a user on Ubuntu with the command "sudo /usr/sbin/adduser demo" (or whatever other name you like in place of "demo").

Chalet commented Mon Jul 14 07:37:46 UTC 2014:

Hey I know tuis is off topic but I waas wondering if yoou knew of any widgets I could add to my blog that automatically tweet my newest twitter updates. I've been looking for a plug-in like this for quite some time and was hoping maybe you would have some experience with something like this. Please let mee know if you run into anything. I truly enjoy reading your blog and I look forward to your new updates.

Visit my blog post ... Chalet

Fabian commented Sun Jul 27 08:32:28 UTC 2014:

If you are going for most excellent contents like I do, only pay a visit this web site daily because it provides feature contents, thanks

Fifa 14 monete hackerare commented Fri Aug 15 20:39:48 UTC 2014:

For the reason that the admin oof this web page iis working, no uncertainty very quickly it will be renowned, due to its quality contents.

Want to comment?

(not made public)


(use plain text or Markdown syntax)