Thu 18 May 2006
Two weeks ago we have started new version of one of our primary web projects and have started very massive advertisement campaign to promote this web site. As the result of that advertisements, our outgoing traffic has been increased to 200-250Mbit/s from only one server! In this article I will describe, how to build stable and efficient web site with two-layer architecture (with frontend + backend web servers) or how to modify your current server configuration to get additional resources to handle more requests.
First of all, let me describe general structure of web-server and how it handles clients requests:
- Client initiates request to your server.
- His browser connects to your server.
- Your server (as for Apache) creates new thread/process to handle request.
- If client requested dynamic content, web server spawns CGI process or executes dynamic content handling module (i.e. mod_php) and waits while request will be processed. When it receives result web-page, it sends it to client.
- If client asked for some static file, web server sends this file to client
- Client’s browser receives answer, closes connection to web server and displays content.
As you can see, when there are many requests coming to your server, your server needs to create many parallel threads/processes and keep them running while client will close connection. If client has slow connection, web server process will wait too long and resource consumption will increase very fast.
What we can do in such situation? Simple solution is to buy more memory and more CPUs for your server and wait while web server load will crash your server. But there is more efficient solution! You can simply put some small piece of software (nginx, for example) behind your big web server and let it handle all requests to static content and to pass all dynamic requests to primary web-server. With this solution your big server will spawn additional threads/processes only for static pages and it will return answers to small frontend very fast and then can free resources to use them to handle another queries. Small frontend can wait very long time while client will receive his content and will close connection - backend server will not consume resources for such long time!
Here you can see simple diagram of proposed web server configuration:
As additional benefit from such configuration you can get very useful feature of managed downloads that will be described below.
If your server contains some static resources, which can be downloaded not by all users (content provider can provide mp3 files only to users with positive balance or some site can provide downloads only to logged-in users), in generic configuration you need to create some script to handle this downloads and to create some ugly links like http://some.service.com/down.php?file=xxx.mp3 and additionally your users will not be able to resume downloads (except such cases when your script so complex, that it handles Ranges HTTP-header)…
In configuration with nginx frontend, you can create simple URL-rewriting rule, that will pass all requests to pretty URLs like http://your.cool-service.com/files/cool.mp3 to some simple script /down.php automatically and, if this script has returned X-Accel-Redirect header, will send requested file to user automatically with Ranges header support and when user will download his cool content, your backend server can handle other requests. Your users even will not know that your script controls their downloads. Simple diagram for described algorithm is following:
Let me bring your attention to interesting fact: If you only accelerate your site with described technique and do not want to create download control system, you do not need to modify any of your scripts on your backend server! They will work as in original configuration!
So, the last thing you need to boost your web server with nginx reverse proxying technique is following configuration file snipet:
listen 80;
server_name some-server.com www.server-name.com;
access_log logs/host.access.log main;
# Main location
location / {
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
# Static files location
location ~* ^.+.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js)$ {
root /spool/www/members_ng;
}
}
Full version of sample config file you can get here.
Notice: If your backend scripts are using user IP addresses for some purposes, you will need to install mod_rpaf module to use X-Real-IP header provided by nginx instead of real user’s IP address.
That is all! Now you can simply install nginx on your server, configure it and your server will be able to handle more traffic with the less resources that it uses now! Everything will be done transparently for your currently written scripts and if you want, you will be able to provide download handling with simple trick, that I will describe in my next post
If you have some questions, do not hesitate to ask them here in comments - I will try to answer all of them. If you liked this article, you can support author by taking a look at advertisements on this page or simply vote for it on digg.com.
- HAProxy - The Reliable, High Performance TCP/HTTP Load Balancer
- Typical Configurations Overview For Nginx HTTP(S) Reverse Proxy/Web Server
- Using X-Accel-Redirect Header With Nginx to Implement Controlled Downloads (with rails and php examples)
- MySQL Proxy Released
- Monitoring nginx Server Statistics With rrdtool

2006-06-07 at 5.12 pm
cool i love alex
2006-07-29 at 5.15 pm
А как избавиться после ридеректа на apache от нолмера порта в урле? В моём случае http://greg.dobroe.net:8080/pma/
2006-07-29 at 7.08 pm
2greg: Использовать директиву proxy_redirect.
2006-08-31 at 2.11 am
Подскажите пожалуйста, как сделать так, чтобы из определённой папки nginx отдавал файлы “как есть” - картинки - картинками, скрипты - файлами (download), не переадресовывая запрос. Т.е. цель - запрет исполнения всего в папке, но возможность скачивания без ошибок. Переопределение типа на application/octet-stream для этой папки результата не даёт
2006-08-31 at 2.51 am
2Thegirl: И оно действительно отдает application/octet-stream? Проверьте через curl/GET/wget…
2006-11-01 at 5.44 am
[...] You would be able free some resources on server while nginx will handle all slow requests to dynamic content (details are here). [...]
2006-11-08 at 3.28 pm
Алексей, добрый день.
как с этим бороться?
Возникла ситуация:
есть один тяжёлый проект
бежит это на nginx
добавили несколько дополнительных серверов с FastCGI
происходит потеря сессий
Заранее благодарен за ответ.
2006-11-08 at 6.16 pm
Что вы имеете ввиду под “потеря сессий”? Если то, что пхп-шные сессии перестали работать, так это логично - они ведь в файлах во дефолту хранятся. Решений я знаю как минимум 2:
1) хранение сессий на nfs-share
2) хранение сессий в базе данных
2006-12-20 at 5.35 am
A quick config question…
I’m reverse proxying to an Apache server…when I run a script that takes a lil’ while to produce some input (e.g. an Amazon product fetching script) nginx will sometimes not present the output, even though the Apache script is still churning away in the background. What timeout setting do I need to adjust in this situation?
2007-01-22 at 7.35 am
Очень познавательно, теперь я знаю, что такое nginx.
2007-02-27 at 7.27 am
Спасибо Алекс, очень полезная статья.
Расскажите плз чем вы такие красивые блок схемы строите?
2007-03-03 at 11.10 am
Ребят, помогите, пожалуйста! никак не могу “подружить” nginx с апачем
у нас на сервере крутятся два сайта.
скажем, q5Video.ru и q5Magazine.ru
в конфиге nginx я прописываю код:
server {
listen 81.17х.х.хх:80;
server_name q5Magazine.ru http://www.q5Magazine.ru;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
# Static files location
location ~* ^.+.(midi|wav|flv|bmp|rtf|js)$ {
root /spool/www/members_ng;
}
и в кофиге апача прописываю
listen 127.0.0.1:8080
что здесь неправильно?
2007-03-10 at 12.14 pm
I wonder if it makes sense to use nginx as a server for static files _behind_ an existing Apache frontend. If have an Apache configuration with several virtual hosts and set it up to proxy requests for static files to nginx, but from what I read on the web everyone else does it the other way around.
Would my setup be less effective under heavy load conditions?
2007-03-10 at 6.07 pm
2rubyrobot: Your configuration would not help to handle higher loads… Idea of nginx-before-apache scheme is in following: nginx would handle lots of traffix and apache would not even know about this traffic.
2007-03-13 at 1.09 pm
scoundrel: I am not sure if that’s the right thing for me. More then 90% of requests are dynamic on my server. There’s only a few requests to large static files, about 200MB in size. If I put nginx in front, it produces a lot of unnecessary overhead, because 90% of requests go straight through the nginx proxy.
I am under the impression that a time consuming 200MB request proxied through Apache to nginx will not keep one of Apache’s large child processes busy that could be better used to process dynamic content. While nginx serves the static file, Apache is free to handle it’s dynamic files. Please correct me if I’m wrong!
2007-03-15 at 4.34 am
I use nginx as a proxy server for Apache Tomcat,and found that the performance is slow down to half of only running Tomcat,So I dont know why was that ?
The configuration like:
location / {
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
who can help me this
2007-04-09 at 10.24 am
Спасибо за статью! Жаль только ни слова не было сказано насчет апача, достаточно ли его только перевесить на другой порт (Listen :8080), и что-то еще нужно поправить?
А в конфиге nginx есть возможность построить условия (анализ HTTP-заголовков), на которых уже решать, что сделать с запросом, проксировать его апачу, или выдать 403?
2007-06-10 at 10.33 am
Статья отличная, но у меня не получается сделать так чтобы картинки отдавались в многопоточном режиме клиенту, т.е. они грузятся на странице по одной, я видел много ресурсов где явно видно что картинки отдаются по несколько сразу и отдаются они нгинксом, или такое только средствами nginx не реализовать.
2007-06-15 at 7.40 am
how to config the simple balancer
use nginx as frontend
use two tomcats as backend web servers
location /
proxy_pass
http://127.0.0.1:8080/;
http://127.0.0.1:9000/;
listen 80
2007-06-22 at 12.07 pm
К сожалению данная схема не работает если на серваке крутятся виртуальные хосты, которые “сидят” на одном айпишнике. ((
Как быть в этой ситуации ?
Спасибо !
2007-06-26 at 4.33 am
Запустил вчера сервер с Вашим конфигом и сервак “умер”. Точнее начались такие тормоза что работать было просто невозможно.
У меня на серваке 8 виртуальных хостов, с которых раздаётся контент(музыка, кино и т.д.) Хотел при помощи нгинкс разгрузить апач, который временами виснет из-за огромного (около 2000) количества процессов. Перевесил каждый виртуальный хост на 127.0.0.1 на разные порты. Настроил нгинкс по Вашему примеру.
После запуска смог зайти более менее быстро только на один сайт. Побродить по нему и тем более что-то качнуть не удалось.((
Помогите разобраться в чём причина таких тормозов и как ускорить систему.
Система
Intel(R) Pentium(R) 4 CPU 2.40GHz
Память - 2 Гб
Ось -Fedora Core 5 - 2.6.20-1.2320.fc5
Apache - 2.2.2
Nginx - 0.5.26
Конфиг полностью совпадает с Вашим, за исключением папки root, конечно )
Жду ответа…
2007-06-27 at 8.44 pm
I’ve used tux on RH before to serve static content the same way(before apache), does any one know how much tux is faster/slower than nginx?
2007-06-28 at 12.59 pm
Hi!
Is’t possible to configure it to use DNS resolution for the backend servers?
I would like to have Nginx to relay http/https for many services on different servers in the backend, but not having to add seperate sections for each server/service.
Or will I lose something by doing that “if possible”?
2007-07-26 at 1.00 am
Is there any specific reason for using Apache as the behind server?
Why wouldn’t you have Nginx as the front and the backend server?
Is there any disadvantage to using Nginx for the dynamic content as well?
2007-07-28 at 4.24 pm
2 Egenius:
у меня крутится около полутора десятков виртуальных хостов через nginx и apache.
Nginx сидит на 80-м порту, apache - на 8080. Никаких проблем, всё отлично.
Очень большие тормоза были при первом заходе на сайт (после установки nginx как frontend) - сайт открывался больше двух минут. Но как только он открылся, всё стало работать очень шустро и быстро и до сих пор радует меня скоростью.
Конфиг - примерно такой же, как в статье, единственное, proxy_redirect использую.
Так что Вы, скорее всего, просто не до конца разобрались в конфигурации - советую обратиться к первоисточникам, и не использовать чужие конфиги.
2007-08-14 at 11.46 am
Добрый день.
А ктонибудь делал связку nginx + java?
2007-08-24 at 5.08 am
2 Egenius:
у меня была такая же ситуация. очень большой iowait.. оказалось что нагрузка сильно растет если отдавать файлы из пхп скриптов fopen, fread.. как только переделал XAccel нагрузка резко упала и использование нгинх оправдалось.
2007-10-01 at 2.23 pm
Доброго времени суток !
У меня такой вопросик …
Есть сайты на MS SharePoint`е в которих забиты внутрение адреса типа http://serv1.localnet/.
И есть сервак на FreeBSD с выходом в инет, который имеет свой адрес http://some.host.net/.
Возможно ли настроить nginx на замену адресов с http://serv1.localnet/ на http://some.host.net/ в страничках, и будет ли это так работать ?
2007-10-02 at 6.56 am
hi.. thanks for all the great posts.
anyone ever configured nginx with haproxy? i would like to use nginx to serve static content and have haproxy load-balancing my mongrels serving 3 clusters. so that nginx gets request (serves if static) if not goes to HA for a proxy to the backend mongrel server.
2007-10-02 at 3.42 pm
Fritzie: Why would you like to use haproxy for balancing when nginx has its own embedded balancing feature?
2007-10-02 at 11.52 pm
doesn’t nginx use a round robin type of balancer. haproxy has an actual queue so its much better for lots of traffic. from what i understand about the queue is that it will only give to a mongrel cluster what it can handle.
2007-10-21 at 3.19 am
One of the things it keeps me worried about using a reverse proxy
is the reporting of visitors statistics.
Where will you take that information from? From the first (frontend)
web server? or from the servers behind it? What information will be
given? Will all the reports look like if the only visitor was the
reverse proxy server?
2007-11-09 at 8.49 am
Каково ограничение на максимальный размер отдаваемого файла?
2007-12-18 at 2.58 pm
Привет,
А есть способ сделать так, чтобы nginx вместо того, чтобы обслуживать:
location ~* ^.+.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js)$ {
root /spool/www/members_ng;
}
обслуживал все файлы, кроме .jsp и случая когде не указано расширение. Т.е. запрос к папке идёт.
Ну и папку /WEB-INF заоодно закрыть
2007-12-25 at 8.53 am
Менять в скриптах все же прийдется. Скажем взять PHP:
Таким образом, после редиректа, получится, что $HTTP_SERVER_VARS[PORT] = 8080, но это пол беды, т.к. это мало кому важно, гораздо страшнее следующая проблема:
При проксировании SSL мы получаем SERVER ENVIRONMENT
HTTPS = null
и
SERVER_PORT = 8080
При редиректе на какой-нибудь пеймент метод(не на все, но такое бывает), кастомер отредиректиться обратно(после проверки кредитки) на порт 8080. Плюс Corner of Trust и подобные штуки для верификации SSL-сертификата, внушающие доверие покупателям тоже могут не работать…
Решается такая проблема магическим RewriteRule’ом:
RewriteEngine on
RewriteCond %{HTTP:SSL} YES
RewriteRule .* - [E=HTTPS:on,L]
RewriteRule .* - [E=SERVER_PORT:443,L]
good luck
2008-01-05 at 9.55 pm
А разве точку в location не надо заслешить? Работать оно, конечно и так будет.
2008-01-06 at 12.10 pm
> anyone ever configured nginx with
> haproxy?
http://www.nginxhosting.com
2008-01-21 at 4.37 pm
не могу настроить слушать апач адрес 127.0.0.1:80
когда пишу
Listen 127.0.0.1:80
то он выдает ошибку
(98)Address already in use: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
что делать?
2008-01-23 at 7.02 pm
[...] should then fill it with the following configuration, courtesy of Alexey Kovyrin. Of course, you’ll need to change a few things to fit your specific setup, such as the domain [...]
2008-02-05 at 1.52 pm
Есть такая проблемка:
nginx, слушает somehost:6969
бэкэнд, на который перекидываются запросы
proxy_pass http://127.0.0.1:4850;
суть проблемы, бэкэнд посылает Location: /welcome, однако Proxy его перезаписывает как somehost/welcome, при этом теряется порт (6969)
собственно, что надо сделать с proxy_redirect, чтобы либо он оставался относительным, либо не терялся номер порта?
заранее спасибо
2008-03-01 at 4.11 pm
Everything works but I have done some benchmark tests with apache tool “ab” and nginx performs excellent with static files but when it has to proxy request to the Apache listening on 127.0.0.1:8080 for simple .php file it is drastically slower than Apache running solo.
Since, 70-80% of my sites are PHP based this practically dismisses nginx for me.
Or I am doing something wrong?
2008-03-28 at 6.16 am
[...] Начну с примера: есть сайт, который позволяет зарегистрированным пользователям скачивать что-либо (музыку, программы, фильмы — не суть важно). Одним из самых распространённых решений в этом случае является использование нескольких серверов. Во многих конфигурациях, которые я видел, “web-мордой” занимается Apache, а на обслуживании закачек стоит nginx+PHP+FastCGI (PHP занимается вопросами авторизации, ведения статистики и т.п.). Сразу оговорюсь, что есть альтернативное решение, когда nginx используется в качестве reverse proxy перед Apache — nginx проксирует запросы к PHP-скриптам Apache, а PHP-скрипт, если ему надо отдать что-то статическое, делает X-Accel-Redirect. Подробнее описано в статьях “Использование X-Accel-Redirect с Nginx для реализации контролируемых скачиваний” и “Использование Nginx Как Reverse-Proxy Сервера На Загруженных С…”. [...]
2008-04-17 at 7.24 am
Подскажите как при помощи nginx решить такую проблему: за nginx стоит apache, который в свою очередь периодически отключается мною. Хотелось бы чтобы во время выключения апача пользователи получали созданную мною html страничку с приличным текстом, а не страницу браузера, о том что не возможно подключиться к серверу.
location / {
proxy_pass http://localhost:8888/
….
….
}
2008-05-19 at 8.40 am
2Антон
Попробуй обработать 504 ошибку в nginx
2008-06-07 at 8.13 pm
[...] we decided to use nginx in what’s called a reverse-proxy. When you make a request to our Web server, nginx handles that request. It checks to see if the [...]
2008-07-16 at 2.45 pm
Статься прекрасная, но не полная.
Для полноты автору следовало бы описать и настройку Apache чтобы он не конкурировал с nginx, и нормально ловил подачи nginx