Back to Home

Experience setting up nginx on Debian

nginx · memcached

Experience setting up nginx on Debian

    Last night I dedicated the fuss with the nginx http server as a frontend to apache. As you know, nginx is a lightweight reliable HTTP server written by Igor Sysoev ( Rambler employee ). It is great for generating static pages, especially under load. Usually, the nginx + apache bundle is configured, in which nginx serves all requests coming to the server, gives out static files on its own, and proxy requests for dynamic content on apache.

    So, on setting up the work of this pair in a bunch on the Internet, there are a lot of articles, including in Russian, and it makes no sense to write about it. And I’ll tell you better about the nuances that I encountered yesterday when configuring nginx to work in the right mode, and at the same time I will show and comment on my configuration of this server.


    My configuration


    For starters, what actually needed to be done? The server was configured for the Habrometer . It was supposed to produce statics (logo and css) and dynamics (the actual site pages and png-hubmeters). At the same time, it was necessary to take into account that the habrometer is created on the fly in the event that it does not lie in the cache (and the cache is cleaned every 2 hours when requesting new data). Site pages also need to be cached. That was such a task.

    It was decided to implement the implementation as follows. nginx when processing the request should follow the following rules:
    1. If statics is requested, then just return it (all the statics in the stuff daddy).
    2. If a site page is requested, check the cache; if the file is not found in the cache, pass the request to the apache backend. The page cache should be cleaned at a given frequency (for different pages, the frequency is different).
    3. If an informer is requested, then you need to check the cache for the presence of a file. If the file is not there, send the request to the backend.

    For caching of habrometers the file system is selected. All generated informers are added to the / image_cache / directory and it is cleaned every 2 hours when updating the source data. Informers are drawn and put into this directory by a PHP script upon request.

    Memcache was selected for caching site pages, as it is easy and convenient to work with it (both from nginx and from PHP) and he can clean cached pages at a given time interval, which the FS cannot do without additional scripts. Yes, and memcache will work faster, because All good is stored in RAM.

    The following server configuration was obtained:

    # cat /etc/nginx/nginx.conf
    user www-data;
    worker_processes 4;
    error_log /var/log/nginx/error.log;
    pid /var/run/nginx.pid;
    events {
        worker_connections 1024;
    }
    http {
        include /etc/nginx/mime.types;
        default_type application / octet-stream;
        access_log /var/log/nginx/access.log;
        sendfile on;
        keepalive_timeout 65;
        tcp_nodelay on;
        gzip on;
        add_header Habrometr "hacker_mode_enabled;)";
        server {
            listen 80;
            server_name habrometr.server.valera.ws habrometr.ru www.habrometr.ru;
            access_log /var/log/nginx/habrometr.access.log;
            location / {
                root / home / habrometr / public_html;
                index index.html index.htm;
                if (-f $ document_root / image_cache $ {uri}) {
                    rewrite ^. * $ / image_cache / $ uri last;
                    break;
                }
                set $ memcached_key "habrometr $ uri";
                memcached_pass localhost: 11211;
                # if a resource is not found in memcached, send a request for Apache
                error_page 404 502 504 = @backend;
                add_header Content-Type "text / html; charset = UTF-8";
                gzip on;
                gzip_proxied any;
                gzip_types application / octet-stream;
        }
        location @backend {
            set $ proxy_uri http://habrometr.ru:99999$request_uri;
            proxy_pass $ proxy_uri;
            proxy_redirect off;
            proxy_set_header X-Real-IP $ remote_addr;
            proxy_set_header X_Forwarded-For $ proxy_add_x_forwarded_for;
            proxy_connect_timeout 20;
        }
        location / image_cache / {
            root / home / habrometr / public_html;
            expires modified + 2h; # cache expires 2 hours after file modification
        }
        location / stuff / {
            root / home / habrometr / public_html;
            expires 30d;
        }
        location ~ /\.ht {
            deny all;
        }
    }

    Given the above scenario, the entire configuration should be clear. I only note that habrometr.ru : 99999 is an apache to which requests will be redirected. Of course, I changed the port, in reality they usually use 8080 or something like that.

    Magic tricks


    And now that is non-trivial in this configuration (at least for a beginner in this field).

    Version


    Firstly, my server runs on Debian 4.0. I naturally installed all the software from standard repositories. Delivered from there and nginx. Installed nginx turned out to be version 0.4 with the latest version 0.7 with a significant list of changes .

    It turned out that version 0.4 is not able to do much of what was needed. In particular:
    1. the modified flag does not exist for the expire directive, but it was necessary for me to indicate the expiration time of the informers cache (2 hours after creation: expire modified + 2h);
    2. proxy_pass did not know how to use variables, but I needed this feature;
    3. memcached did not use the $ memcached_key variable to determine the key, i.e. it was impossible to set a key of the required format.

    In principle, all these problems could be solved by perverse ways, but I didn’t want to do this at all, so I just installed the latest version of nginx from raw materials. Fortunately, this is done very simply.

    Before describing the installation process, I note that by default, when building from source, all nginx files are added to the / usr / local / nginx directory. It can of course be changed (--prefix =). But note that the nginx installed from the packages scatters its files in the corresponding system directories (/ etc, / var / log, / var / run, etc.), which I personally definitely like more than / usr / local / nginx / *. Therefore, I compiled nginx from raw sources with settings for system directories, and then instead of make install, I simply manually replaced the old server binary in the / usr / sbin directory with the new one (/ usr / sbin / nginx). There are no more significant files after the build for the server. The config, of course, remains the same.

    So, installing nginx on Debian etch from the sources on top of the installed package of the old version.
    # wget http://sysoev.ru/nginx/nginx-0.7.31.tar.gz
    # tar xzf nginx-0.7.31.tar.gz
    # cd nginx-0.7.31
    # apt-get install libpcre3 libpcre3-dev libpcrecpp0
    # /etc/init.d/nginx stop;
    # ./configure --sbin-path = / usr / local / sbin --with-http_ssl_module
    --without-mail_pop3_module --without-mail_imap_module
    --without-mail_smtp_module --prefix = / var / lib / nginx
    --sbin-path = / usr / sbin --conf-path = / etc / nginx /
    --error-log-path = / var / log / nginx --http-log-path = / var / log / nginx
    --pid-path = / var / run --lock-path = / var / lock
    # cd objs
    # cp -f ./nginx / usr / sbin
    # /etc/init.d/nginx start;

    After that, a fresh nginx server should be started and serve requests, which can do all the things we need.

    Documents from memcached


    When nginx gives files directly, it passes the Content-type header according to the type of the given file. When nginx proxies apache, the Content-type comes from apache. But when nginx picks up a document from memcached, the Content-type is not set. So, the default one is used. And the default one in our config is default_type application / octet-stream ;, and this is correct. In this case, when the document is sent from the cache, the type will be transferred incorrectly and some browsers will suggest saving the binary file instead of opening the HTML page. To fix the situation, in case of recoil from memcached, we set the headers (and, by the way, compression too) additionally:
    set $ memcached_key "habrometr $ uri";
    memcached_pass localhost: 11211;
    error_page 404 502 504 = @backend;
    add_header Content-Type "text / html; charset = UTF-8";
    gzip on;
    gzip_proxied any;
    gzip_types application / octet-stream;

    At the same time, from memcached we get only HTML in UTF-8.

    Flies separately, cutlets separately.


    As a separate magic, I would like to single out the very method of selecting habrometers by file name and serving them in a special way. In the location / section, select these files:
    if (-f $ document_root / image_cache $ {uri}) {
        rewrite ^. * $ / image_cache / $ uri last;
        break;
    }

    If we find the file in the cache, then simply return it to the user, saying that the file can be cached before the next update (file modification + 2 hours):
    location / image_cache / {
        root / home / habrometr / public_html;
        expires modified + 2h;
    }

    Note the rewrite last flag and the break directive; for her. Without using these two directives, I was unable to force nginx 0.4 (I did not check for 0.7) immediately go to the location / image_cache / section, i.e. after detecting the file, he proceeded to scanning, which is incorrect.

    Read Next