El servidor web

Un servidor web es un programa que responde peticiones HTTP en algún puerto TCP, normalmente el 80. Existe en la actualidad varias implementaciones populares, entre las que sobresalen Apache HTTP Server, Microsoft Internet Information Services (IIS), y nginx. Este capítulo utilizará nginx a modo de ejemplo.

5 pts. Repase la sección Arquitectura web del material de apoyo del curso, en especial los temas "El servidor web" y "El protocolo HTTP".

Instalación y ejecución del servidor web

La instalación de un servidor web es un proceso muy dependiente de la implementación escogida y de las necesidades del autor. En el caso de los servidores web libres, el método ideal es obtener el código fuente, instalarlar sus pre-requisitos, configurarlo (en especial para habilitar los módulos que se van a utilizar), compilarlo, e instalarlo. Este procedimiento tipicamente se documenta con detalle en el sitio del servidor web. Por otra parte, tanto los servidores web libres como propietarios distribuyen binarios que son relativamente fáciles de instalar, pero los módulos o extensiones que traen preestablecidos son los escogidos por quien generó el ejecutable y no necesariamente coinciden con los que el desarrollador web necesita.

5 pts. Instale nginx en su máquina local. Para propósitos de este laboratorio una versión binaria será suficiente. Si trabaja con Linux, utilice el administrador de paquetes de su distribución, por ejemplo, en Debian/Ubuntu bastará con el comando:

sudo apt-get install nginx

Si desea obtener la última versión, agregue el repositorio de nginx a su administrador de paquetes como se explica en la página de descargas de nginx. Si utiliza Windows, descargue una versión estable del sitio oficial de nginx. Descomprímala en cualquier lugar de su disco duro.

Una vez instalado el servidor web es necesario ponerlo en marcha. En el caso de nginx basta con invocar su ejecutable. El usuario notará que al hacerlo el programa termina inmediatamente dando la sensación de que nada ocurrió. Sin embargo, nginx habrá iniciado al menos dos procesos homónimos en segundo plano (background), los cuales estarán esperando solicitudes HTTP en el puerto 80. Esto se puede probar con un navegador que acceda a la dirección http://localhost.

5 pts. Ponga en marcha su servidor web. En el caso de Windows corra con permisos de administración el ejecutable que descargó. Si no tiene permisos de administración, edite el archivo conf/nginx.conf y cambie la directiva listen 80 a un puerto superior a 1024, por ejemplo listen 8080; luego corra el ejecutable normalmente. En el caso de Linux puede ocurrir que su administrador de paquetes ya lo haya puesto en ejecución. De lo contrario invóquelo con permisos de administración:

sudo nginx

Si el ejecutable nginx no está en el $PATH, deberá localizar su ruta completa con el administrador de paquetes, por ejemplo en Debian se obtiene con dpkg -L nginx-full. Sin embargo, los administradores de paquetes asumen que el servidor debe iniciarse cada vez que arranca la computadora, por lo que estará en algún "init level", y como cualquier otro demonio se puede arrancar con:

sudo /etc/init.d/nginx start

Finalmente pruebe con un navegador que su servidor web responda en http://localhost.

Desde el punto de vista de la interacción con el usuario hay dos tipos de programas: (1) los programas en primer plano (foreground) que mientras están en ejecución mantienen un diálogo con el usuario; y (2) los programas en segundo plano (background) que no esperan una interacción directa con el usuario, como por ejemplo, el núcleo del sistema operativo, servicios de acceso a la red, demonios que ejecutan tareas programadas, servidores de correo, FTP, etc. El servidor web cabe en esta segunda categoría.

Cuando nginx es ejecutado arranca al menos dos procesos. El primero se llama nginx master process y debe ser ejecutado con permisos de administración, ya que por política de Unix, sólo procesos iniciados por el superusuario pueden abrir sockets en cualquier puerto, mientras que los iniciados por usuarios normales, sólo pueden escuchar en puertos superiores a 1024. El segundo y demás procesos reciben el nombre de nginx working processes, son procesos iniciados por nginx a nombre de un usuario cualquiera (especificado en la configuración de nginx) que atienden un cliente web en cualquier otro puerto, con el fin de liberar el puerto 80 para que esté disponible y poder aceptar más conexiones.

Si se invoca el ejecutable de nginx sin parámetros, tratará de iniciar el servidor web. Si se invoca por segunda vez sin parámetros, fallará ya que el puerto 80 estará en uso. Si se invoca con el parámetro nginx -h brindará ayuda. La opción nginx -V permite ver la versión y los módulos con que fue compilado el ejecutable. La opción nginx -s sirve para controlar al servidor en ejecución. Otras opciones se discutirán más adelante.

5 pts. Utilizando parámetros del ejecutable nginx, detenga la ejecución del servidor y pruebe su efecto en el navegador; determine la versión que tiene instalada en el sistema y los módulos que puede habilitar. Compare contra la lista de módulos disponibles si existe alguno que necesite o esté interesado(a). Si el módulo no está en la lista de instalados, deberá compilar nginx desde el código fuente.

Configuración del servidor web

Una vez instalado el servidor web, el autor querrá configurarlo para hacer funcionar su sitio. Tareas como indicarle al servidor web dónde están los documentos que conforman el sitio, si debe o no habilitar PHP, y cuánto es el número máximo de conexiones (visitantes) que debe permitir simultáneamente, son las que se establecen en la configuración.

La mayoría de servidores web se configuran con directivas en archivos de texto. Desdichadamente cada uno tiene sus propias convenciones, en lugar de existir un estándar. En el caso de nginx, el archivo principal de configuración se llama nginx.conf y su ubicación depende de los parámetros con que se compiló el código fuente, o de las convenciones de la distribución de Linux. Por ejemplo, en Ubuntu puede ubicarse bajo la carpeta /etc/nginx/. La nomenclatura de las directivas de configuración de nginx puede visualizarse con el siguiente pseudocódigo:

# Esto es un comentario
nombre_directiva valores;

# Un modulo se configura con un bloque de directivas
nombre_modulo
{
   directiva2 valor;
   directiva3 valor1 valor2;
   # ...
}

Las directivas constan de un término que significa alguna característica para nginx, seguido por uno o más valores. El término y los valores se separan por espacios en blanco. Como es de esperar, nginx está dividido en muchos módulos: core, webdav, fastcgi, mail, etc., y cada uno tiene directivas para configurarlos. Las directivas de cada módulo se escriben en el archivo de configuración agrupadas dentro de llaves { }, lo que forma un bloque de directivas (directive block), y son precedidos por el nombre del módulo. Esta práctica mantiene el orden e incrementa la legibilidad. El nginx_config_file1 muestra un fragmento de un archivo de configuración de nginx.

user www-data;
worker_processes 4;
pid /var/run/nginx.pid;

events
{
   worker_connections 768;
   # multi_accept on;
}

http
{
   # Basic settings
   include /etc/nginx/mime.types;
   default_type application/octet-stream;

   # Logs
   access_log /var/log/nginx/access.log;
   error_log "/var/log/nginx/error.log";

   # Virtual host configs
   include /etc/nginx/conf.d/*.conf;
   include /etc/nginx/sites-enabled/*;
}
Un archivo de configuración de nginx

La configuración del nginx_config_file1 dice lo siguiente a nginx. Cuando nginx master process es invocado por un administrador (o en el arranque del equipo), lanzará cuatro nginx working process (línea 2), cada uno a nombre del usuario www-data del sistema operativo (línea 1), y cada uno será capaz de atender a lo sumo 768 conexiones con navegadores (línea 7). Esta configuración puede ser conveniente para una máquina con un procesador de cuatro núcleos. Las líneas 11 a 24 configuran el módulo http, el cual se estudia más adelante.

A un modo más sintáctico, la directiva en la línea 7 del nginx_config_file1 sólo afecta al módulo de eventos (Events Module) de nginx; mientras que las directivas que no están dentro de llaves (líneas 1 a 3) se dice que están en el bloque principal (main block) y tienen un efecto global en el servidor web. Algunas directivas esperan valores numéricos como worker_processes en la línea 2, otras cadenas de caracteres como access_log y error_log en las líneas 18 y 19. Las cadenas se pueden escribir literalmente, pero si tienen espacios en blanco, puntos y comas, u otros caracteres especiales, deberán encerrarse entre comillas dobles o simples. El símbolo de número (#) sirve para crear comentarios (líneas 8, 13, 17, 21).

Los módulos de nginx son opcionales, es decir, se pueden instalar o no, y si están instalados se pueden habilitar o no; a excepción de tres módulos: Core module, Events module y Configuration module, los cuales siempre están instalados y siempre habilitados, ya que proveen la funcionalidad mínima de nginx.

Una diferencia con otros servidores web, y a la vez, un cuidado importante que debe tenerse al modificar los archivos de configuración de nginx es que, nginx se negará a trabajar si la configuración tiene errores. Esto es, si está apagado nginx no arrancará, o si está en ejecución no se apagará. nginx provee la opción nginx -t para probar la configuración. Si el administrador lo desea, puede copiar el archivo de configuración a un archivo cualquiera, modificarlo y probar que sea válido con nginx -t -c config.file, hasta que sea válido y en tal momento, reemplazar el archivo de configuración original.

La directiva include

Una instalación de un servidor web puede utilizarse para uno o más sitios web. No es aconsejable que la configuración de todos esos sitios se haga en el mismo archivo, puesto que se hará voluminoso y difícil de mantener. En su lugar, se recomienda distribuir la configuración en varios archivos que contengan directivas coherentes, al menos un archivo por cada sitio web que deba servir la instalación de nginx.

La directiva include recibe un nombre de un archivo (el cual debe existir) y le indica a nginx que debe insertar el contenido literal de dicho archivo en el lugar donde se encuentra la directiva include. La línea 14 del nginx_config_file1 muestra un ejemplo. El nombre del archivo puede ser un patrón con los caracteres comodines * y ? (filename globbing), que indica a nginx incluir, no un archivo, sino todos aquellos que cumplan el patrón. Por ejemplo, la línea 22 del nginx_config_file1 indica a nginx importar en ese lugar todos los archivos que terminan en *.conf que se encuentran en la carpeta /etc/nginx/conf.d/.

El módulo HTTP Core

El módulo HTTP de nginx es opcional, por lo que puede deshabilitarse, sin embargo, es quizá el más requerido por el autor y el que querrá configurar primero para hacer funcionar su sitio web. Es también el módulo más extenso de nginx y su configuración se hace con tres bloques: http, server y location, como se muestra en el ejemplo del nginx_http_module_config. Las directivas que se escriban directamente en el bloque http { ... } afectan a todo el módulo HTTP, como la línea 3 del nginx_http_module_config, que indica a nginx comprimir los recursos antes de enviarlos al cliente. El bloque server {} sirve para crear servidores virtuales, y el bloque location {} para aplicar una configuración especial a un subconjunto de un servidor virtual, como se explica en las secciones siguientes.

http
{
    gzip on;

    server
    {
        server_name miempresa.com www.miempresa.com;
        listen 80;
        root /home/sites/miempresa.com;

        location /download/
        {
            gzip off;
        }
    }

    server
    {
        server_name portal.miempresa.com;
        root /home/sites/portal.miempresa.com;
        index index.php index.html;
    }

    server
    {
        server_name svn.miempresa.com;
        root /home/svn;
    }
}
Ejemplo de configuración del módulo HTTP de nginx

Servidores virtuales

Un servidor web puede alojar uno o varios sitios web, los cuales se acceden con diferentes dominios. Por ejemplo, una misma instalación de nginx podría servir la página pública de la empresa (www.miempresa.com), un sitio para empleados, clientes y proveedores de la empresa (portal.empresa.com), y un sitio con repositorios de Subversion (svn.miempresa.com). Es deseable poder configurar cada uno de esos sitios independiente de los demás. Por ejemplo, cada uno debe tener un diferente directorio físico donde se encuentran sus recursos, para los dos primeros podría ser importante tener PHP habilitado, mientras que para el segundo el módulo WebDAV, y así por el estilo.

nginx, y en general todos los servidores web, representan cada sitio web como un servidor virtual, es decir, como un pequeño servidor web que corre bajo el auspicio del servidor web real, con su propia configuración independiente de los demás servidores virtuales. Si sólo se quiere montar un único sitio web en un servidor web, lo normal es crear un servidor virtual para dicho sitio, con el bloque de directivas server { ... } dentro del bloque http { ... }.

El nginx_http_module_config define tres servidores virtuales y por ende tres sitios web (líneas 5, 17 y 24). Cuando el servidor web recibe una solicitud de un recurso, debe tener algún mecanismo para determinar a cuál de todos sus servidores virtuales corresponde, lo cual se hace con las directivas listen y server_name. La directiva listen le indica a nginx en cuál puerto TCP, o dirección IP, espera conexiones para ese servidor virtual, de esta forma se puede tener dos sitios web con igual dominio pero diferenciados por el puerto. Si se omite, se asume el puerto 80.

La directiva server_name hace que el servidor virtual responda a uno o más nombres de dominio. Cuando nginx recibe un mensaje de solicitud, revisa el atributo Host: en el encabezado HTTP, y compara su valor contra todos los servidores virtuales para determinar cuál debe responder. En nuestro ejemplo, si nginx recibe el siguiente mensaje HTTP (recuerde que los cambios de línea son importantes):

GET /login.php?remember_user=yes
Host: portal.miempresa.com:80
User-Agent: Opera/11.01 (iOS)


no podrá utilizar el puerto o la dirección IP como criterio para seleccionar el servidor virtual, pero sí el dominio. En este caso, sólo el segundo servidor virtual atiende el dominio portal.miempresa.com en el puerto 80, por lo que nginx cargará el recurso /home/sites/portal.miempresa.com/login.php?remember_user=yes y lo retornará en un mensaje de respuesta HTTP. La directiva server_name acepta comodines, por lo que un servidor virtual podría antender todos los dominios que terminen en o tengan una cadena particular, como:

server_name *.miempresa.com; # or
server_name *miempresa.*; # or
server_name *miempresa*;

La directiva root le indica a nginx dónde se encuentran físicamente los recursos que deben ser servidos a través de un servidor virtual. Es seguido por una ruta, normalmente absoluta, de lo contrario se tomará como relativa al directorio donde está instalado nginx.

La directiva index le indica a nginx cuál recurso o archivo escoger para retornar al cliente cuando se solicita un directorio. Si se especifican varios archivos, se retornará el primero que se encuentre. A este recurso se le suele llamar index page. Por ejemplo, si el servidor web recibe la siguiente solicitud HTTP

GET /admin/
Host: portal.miempresa.com:80
User-Agent: Opera/11.01 (iOS)


de acuerdo a la línea 21 del nginx_http_module_config nginx intentará encontrar el archivo /home/sites/portal.miempresa.com/admin/index.php, si no lo encuentra, intentará con /home/sites/portal.miempresa.com/admin/index.html, y si tampoco existe, responderá con un código de estado de error, posiblemente 404 NOT FOUND. Si en un servidor virtual no se especifica la directiva index, se asumirá index.html.

[Contenido pendiente]

El bloque location

A veces dentro de un servidor virtual, es deseable aplicar una configuración diferente a ciertos recursos del sitio. Los bloques location pattern { ... } permiten escoger un subconjunto de recursos que coincidan con el patrón pattern y aplicarles la configuración que aparece dentro de llaves. El patrón es sensitivo a mayúsculas/minúsculas si el sistema de archivos del sistema operativo lo es también.

MIME types

Cuando el cliente solicita un recurso, el servidor web lo localiza o genera, y debe retornarlo en un mensaje de respuesta HTTP, en el cual debe indicarle al cliente de qué tipo de datos es dicho recurso para que lo pueda interpretar adecuadamente, utilizando una notación estándar llamada extensiones multipropósito de correo de internet (MIME, Multipurpose Internet Mail Extensions), ideadas para el intercambio de archivos por Internet. Por ejemplo, text/html indica un documento HTML, image/png una imagen codificada con el formato PNG, y application/xhtml+xml un documento XHTML.

Póngase en los zapatos del servidor web. Dado un archivo que debe retornar al cliente ¿cómo sabe cuál tipo MIME asignarle en el mensaje de respuesta? nginx se guía por la extensión del archivo, y si no la tiene, asume un tipo MIME por defecto. nginx le permite configurar las asociaciones entre extensiones y los tipos MIME utilizando el bloque types { ... }, como en el nginx_extension_mimes:

http
{
    types
    {
        text/html                    html htm shtml;
        text/css                     css;
        text/xml                     xml rss;
        application/xhtml+xml        xhtml;
        application/x-javascript     js;
        image/gif                    gif;
        image/jpeg                   jpeg jpg;
        # ...
    }

    default_type application/octet-stream;
}
Asociación entre extensiones de archivo y MIME types en nginx

La directiva default_type (línea 15 del nginx_extension_mimes) le indica a nginx cuál MIME type asumir cuando la extensión no se encuentra en el bloque types { ... } o cuando el recurso simplemente no tiene extensión.

5 pts. Compruebe el efecto de servir documentos HTML y XHTML con el MIME adecuado (text/html y application/xhtml+xml respectivamente), y con el MIME inadecuado al intercambiar los dos anteriores. Puede efectuar el experimento como se explica a continuación. Asegúrese de que su servidor web esté configurado para servir archivos con extensión .html con el MIME type text/html (como en la línea 5 del nginx_extension_mimes), y la extensión .xhtml con el MIME type application/xhtml+xml (línea 8 del nginx_extension_mimes).

En su sitio web cree un documento con extensión .html, por ejemplo, html.html cuyo contenido sólo es válido en HTML (como el xhtml_pure_html). Copie el archivo con la extensión equivocada (como html.xhtml). Con un navegador acceda a ambos archivos a través de su servidor web. Luego cree un archivo con extensión .xthml, dígase xhtml.xhtml cuyo contenido sólo sea válido en XHTML (como el html_pure_xhtml_cdata). Copie el archivo con la extensión incorrecta (como xhtml.html), y finalmente pruebe acceder con un navegador a ambos archivos a través de su servidor web.

<body>
    <h1>MIME application/xhtml+xml</h1>
    <p>Si este <strong>documento XHTML</strong> es servido con el MIME
    <code>application/xhtml+xml</code>, abajo se debe ver <em>el código
    fuente</em> que generó este párrafo y no un texto con formato.</p>

    <pre><![CDATA[
        <p>Si este <strong>documento XHTML</strong> es servido con el MIME
        <code>application/xhtml+xml</code>, abajo se debe ver <em>el código
        fuente</em> que generó este párrafo y no un texto con formato.</p>
    ]]></pre>
</body>
Una sección CDATA no debe interpretarse como código (X)HTML cuando el documento es servido como application/xhtml+xml. Correr ejemplo completo.

Server Side Includes module

nginx -y en general todos los servidores web- pueden extender su funcionalidad con módulos, escritos por el equipo oficial, terceros, o incluso usted. En esta y siguientes secciones se explorarán algunos de ellos.

El módulo Server Side Includes (SSI) le indica al servidor web que antes de servir un recurso al cliente, analice (parsing) dicho recurso en búsqueda de comandos para el servidor web, los cuales tienen la notación:

<!--#command parameter1="value1" parameter2="value2" ... parameterN="valueN" -->

Los comandos de SSI se escriben dentro de comentarios de (X)HTML pero antecedidos con un símbolo de número (#). No debe haber espacios en blanco entre el inicio del comentario y el comando, y debe haber espacio en blanco antes de los dos guiones al terminar el comentario. SSI provee varios comandos, pero el más popular es include, de ahí el nombre de SSI.

Por ejemplo, antes de servir el documento del server_ssi_include_example, el servidor web recorrerá su contenido, localizará todos los comentarios que inicien con <--# y tratará de ejecutar el comando que sigue. El comando include le indica al servidor cargar el archivo que se encuentra en el atributo virtual="url", o si es un programa, ejecutarlo. El contenido del archivo o el resultado del programa será insertado en el documento servido, reemplazando el comentario que lo referencia.

<html>
    <head>
        <title>Mi empresa</title>
    </head>
    <body>
        <article id="page">
            <!--#include virtual="header.html" -->
            <!--#include virtual="menu.html" -->
            <article id="content">
                <p>Bienvenidos al ...</p>
            </article>
            <!--#include virtual="footer.html" -->
        </article>
    </body>
</html>
Ejemplo de un documento con comandos include de SSI

El parámetro virtual del comando include recibe un URL hacia el recurso que debe incluirse, aunque probablemente el autor prefiera usar una ruta relativa, como en el server_ssi_include_example, donde todos los documentos deben estar en la misma carpeta. Las implementaciones actuales de los servidores web, permiten referir archivos en la misma carpeta o en subcarpetas a partir de donde se encuentra el documento que tiene las instrucciones SSI, pero no carpetas superiores, es decir, los servidores web ignorarán comandos como el siguiente.

<!--#include virtual="../menu.html" -->

Lo anterior es una gran limitante. Sin embargo, el parámetro virtual permite referir recursos a partir de la raíz del sitio web (/). De esta forma, los autores suelen colocar los recursos incluidos (el encabezado del sitio, pie de página, menú de navegación, etc.) en la raíz del sitio web, o una subcarpeta, y referirlos como en el server_ssi_include_docuement_root.

<html>
    <head>
        <title>Preguntas frecuentes</title>
    </head>
    <body>
        <article id="page">
            <!--#include virtual="/header.html" -->
            <!--#include virtual="/menu.html" -->
            <article id="content">
                <p>Sección de preguntas frencuentes ...</p>
            </article>
            <!--#include virtual="/footer.html" -->
        </article>
    </body>
</html>
Referir documentos utilizando URL relativos a la raíz del sitio web

El autor que quiera utilizar Server Side Includes, deberá habilitar el módulo ssi en la configuración de nginx, e indicarle en cuáles tipos de recursos (MIME types) quiere que el servidor recorra su contenido para localizar y procesar comandos SSI, de lo contrario se asumirán sólo los text/html. Por ejemplo:

server
{
    server_name miempresa.com www.miempresa.com;
    root /home/sites/miempresa.com;

    ssi on;
    ssi_types text/html application/xhtml+xml application/x-javascript;
}

Aunque SSI es muy eficiente y se puede habilitar para todo un sitio web, es mejor evitarlo para archivos que no lo requieren. Una práctica común es nombrar únicamente los archivos que tienen Server Side Includes con la extensión .shtml (contracción de server html), y habilitar el módulo ssi sólo para ellos, por ejemplo:

server
{
    server_name miempresa.com www.miempresa.com;
    root /home/sites/miempresa.com;
    index index.shtml index.php index.html;

    # Habilita Server Side Includes en todos los archivos con extensión .shtml
    location ~* \.shtml$
    {
        ssi on;
    }
}

[Contenido pendiente: demás comandos SSI]

CGI y FastCGI

La publicación de páginas web estáticas se está convirtiendo en una práctica en desuso. La mayoría de sitios web pretenden hacer tan efectiva la comunicación con el lector para que éste se sienta a gusto y ambas partes se beneficien. En este movimiento no basta sólo con programación del lado del cliente con JavaScript, el servidor web también debe ajustarse a las necesidades del visitante y hacer que las páginas que sirva sean dinámicas. Es decir, la fuente de los recursos con los que responde el servidor web no son archivos estáticos, sino el resultado de ejecutar programas de aplicación escritos en cualquier lenguaje de programación. Es evidente entonces que debe existir un conjunto de convenciones que permitan a una aplicación cualquiera -ocupada de la lógica del negocio- comunicarse con un servidor web cualquiera -ocupado de los asuntos de red-, para que así ambos colaboren y respondan al visitante adecuadamente. Este conjunto de convenciones las establece el estándar Common Gateway Interface (CGI) surgido en 1993.

Cuando el usuario solicita un recurso, el servidor web sabe -de acuerdo a su configuración- si el recurso es estático o dinámico. Si es estático lo carga desde la memoria secundaria y retorna una copia al cliente. Si es dinámico, deberá interactuar con una aplicación y es ahí donde entra en juego CGI. CGI es protocolo que impone la forma en que la información se transfiere entre el servidor web y una aplicación cualquiera (llamada gateway application) y se resume en lo siguiente. El servidor web ejecuta el programa de aplicación pasándole por parámetro o en la línea de entrada un conjunto de variables. La aplicación se carga, realiza su lógica del dominio en función de esas variables, consultando bases de datos o cualquier otro recurso, construye una página web, la imprime en la salida estándar y termina su ejecución. El servidor web captura esa salida y la envía al cliente que solicitó el recurso.

El procotolo CGI tiene varios inconvenientes, en especial para sitios web mundialmente concurridos. Por esto a mediados de los 90 se desarrolló el estándar FastCGI, el cual introduce las siguientes diferencias sobre CGI:

  1. CGI ejecuta un proceso de la aplicación por cada solicitud, lo cual puede agotar la memoria del servidor rápidamente, consume procesador iniciando y cerrando procesos, y además los procesos deben implementar complejos mecanismos de intercomunicación si necesitan trabajar en conjunto. FastCGI sólo arranca un proceso de la aplicación al cual le "pasa" todas las solicitudes de uno o más visitantes. La ejecución de la aplicación no es detenida, por lo que se le llama proceso persistente.
  2. En CGI la aplicación y el servidor web deben correr en la misma máquina física, lo cual puede ser indeseable, en especial si el proceso es pesado y se disponen de más computadoras en la organización. FastCGI impone que el servidor web y la aplicación deben comunicarse a través de TCP/IP, así ambos pueden ejecutarse en computadoras distintas, incluso, en redes distantes y con sistemas operativos diversos.

De lo anterior se infiere que la aplicación, indeferentemente del lenguaje de programación en que esté hecha (C, C++, Java, PHP, Ruby, etc.), debe implementar un servidor TCP/IP esperando conexiones en algún puerto, configurar nginx para que cuando se solicita un recurso con una extensión particular o una ruta particular, se contacte la aplicación en dicho puerto TCP. En lo siguiente este proceso se explicará para PHP.

PHP a través de FastCGI

Los programas para PHP no son ejecutables, es decir, no son compilados. Un archivo de texto con extensión .php es interpretado por el ejecutable de PHP (/usr/bin/php ó php.exe), de la siguiente forma:

php /path/to/myfile.php

Lo anterior claramente no es un servidor TCP/IP esperando conexiones en algún puerto, como exige el protocolo FastCGI. El proyecto PHP-FPM (PHP FastCGI Process Manager) es una alteración de PHP para Unix que ejecuta un demonio normalmente en el puerto 9000, el cual espera solicitudes de ejecutar un archivo .php particular con sus respectivos parámetros. nginx puede comunicarse con PHP-FPM a través de FastCGI, lo cual se considera una implementación muy eficiente, ideada para sitios altamente concurridos.

Para instalar PHP-FPM se puede configurar y compilar su código fuente, o utilizar el administrador de paquetes de su distribución de Linux. Por ejemplo, los siguientes comandos instalan y ponen en ejecución un servidor de PHP-FPM en Debian/Ubuntu:

sudo apt-get install php5-fpm
sudo /etc/init.d/php5-fpm start

Ahora debe decirle a nginx que cada vez que un visitante solicita un archivo .php, debe contactar al servidor de PHP a través de FastCGI en el puerto 9000, para que lo ejecute, y el resultado que se genere de su invocación, enviarlo al visitante. Para nuestros efectos, el archivo .php puede estar en cualquier lugar del sitio web, su único distintivo con los demás archivos del sitio es su extensión .php. La siguiente configuración mínima hace este trabajo. Nota: es probable que las siguientes líneas ya estén presentes en la configuración por defecto, basta con quitarles los comentarios.

server
{
    server_name miempresa.com www.miempresa.com;
    root /home/sites/miempresa.com;
    index index.php index.html;

    # Ejecuta todos los archivos con extensión .php antes de enviarlos al cliente
    location ~* \.php$
    {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_index index.php;
    }
}

El bloque location anterior le indica a nginx que antes de servir un archivo con extensión .php, debe contactar a través de FastCGI al programa que está corriendo en el puerto 9000, e indicarle que ejecute el archivo .php. Esto último se indica a través de parámetros con la directiva fastcgi_param NOMBRE_PARAMETRO valor_parametro. Por ejemplo, la directiva en la línea 11 le indica a nginx enviar a PHP-FPM la ruta absoluta del archivo .php en el parámetro SCRIPT_FILENAME. Los valores iniciados con un símbolo de dólar, como $document_root son variables de nginx, las cuales se reemplazan por sus valores respectivos, en el caso de $document_root por el directorio donde están los recursos del sitio web (/home/sites/miempresa.com en este ejemplo), y $fastcgi_script_name por la ruta relativa dentro del sitio del archivo .php solicitado por el visitante. Otros parámetros son necesarios, el archivo fastcgi_params que trae la instalación de nginx se encarga de ellos y funciona para la mayoría de sitios.

Para Microsoft Windows no existe una implementación de PHP-FPM, por lo que el desarrollador puede emularlo a través de Cygwin, o utilizar algún paquete "todo en uno", como Easy WEMP (acrónimo de Windows, nginx, MySQL y PHP).

5 pts. Pruebe que su instalación de nginx-PHP funcione. Cree un archivo info.php con el siguiente contenido en algún lugar de su sitio web:

<?php
    phpinfo();
?>

Solicite el recurso anterior a través de un navegador, por ejemplo, dirigiéndolo a http://localhost/info.php. Si la instalación fue exitosa, verá una extensa página con detalles sobre su configuración de PHP.

Ejemplo: ocultar las extensiones .php

Es una práctica común en muchos sitios web ocultar la extensión (.exe, .php, .cgi, etc.) de los programas que generan páginas web dinámicas, con el fin de hacer los enlaces más legibles, y quizá para proveer menos información a potenciales atacantes sobre la naturaleza del software ejecutándose en el servidor. El nginx_hide_php_extension_config muestra la configuración de nginx de un sitio web que oculta las extensiones de los archivos .php en los URL.

server
{
   listen 80;
   server_name www.miempresa.com;

   index index.xhtml index.html index.php;
   autoindex on;

   ssi on;
   ssi_types application/xhtml+xml;

   location /
   {
      root /home/website/www;
      try_files $uri $uri/ $uri.php?$args;

      location ~ \.php$
      {
         internal;
         fastcgi_pass   127.0.0.1:9000;
         fastcgi_index  index.php;
         fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
         include        fastcgi_params;
      }
   }

   location ~ /\.
   {
      deny all;
   }
}
Ocultar las extensiones .php en un sitio web con nginx