1. Qué hace un servidor web
Un servidor web es el programa que escucha en los puertos 80 (HTTP) y 443 (HTTPS), recibe las peticiones y decide qué hacer con cada una: devolver un fichero del disco, redirigir a otra dirección, pedir usuario y contraseña o pasar la petición a la aplicación que la sabe responder. Es la puerta de entrada de casi cualquier web, y configurarlo bien afecta a la velocidad, a la seguridad y a lo que Google opina de tu sitio.
Los dos más usados son Apache y Nginx, y entre los dos sirven la mayoría de las webs del mundo. Apache nació en 1995 y es extremadamente flexible gracias a sus módulos y a los ficheros .htaccess, que permiten cambiar la configuración carpeta a carpeta. Nginx apareció en 2004 para resolver el problema de atender miles de conexiones simultáneas con poca memoria, y hoy es la opción habitual como proxy inverso delante de las aplicaciones.
| Apache | Nginx | |
|---|---|---|
| Modelo | Procesos o hilos por conexión (MPM prefork, worker, event) | Asíncrono, orientado a eventos: pocos procesos para miles de conexiones |
| Configuración por carpeta | Sí, con .htaccess (cómodo, pero más lento) | No: todo en la configuración central |
| PHP | Integrado con mod_php o mediante PHP-FPM | Siempre mediante PHP-FPM |
| Punto fuerte | Flexibilidad y compatibilidad con alojamientos compartidos | Rendimiento con estáticos y como proxy inverso |
2. Varios sitios en un servidor: los virtual hosts
Un mismo servidor, con una sola IP, puede alojar muchas webs. El truco está en la cabecera Host de cada petición HTTP, que dice a qué dominio va dirigida; el servidor la compara con sus virtual hosts (en Nginx, bloques server) y usa la configuración correspondiente.
Los virtual hosts son buzones de un mismo edificio
1server {
2 listen 80;
3 server_name apuntes.es www.apuntes.es;
4 return 301 https://apuntes.es$request_uri; # todo a HTTPS y sin www
5}
6
7server {
8 listen 443 ssl;
9 http2 on;
10 server_name apuntes.es;
11
12 ssl_certificate /etc/letsencrypt/live/apuntes.es/fullchain.pem;
13 ssl_certificate_key /etc/letsencrypt/live/apuntes.es/privkey.pem;
14
15 root /var/www/apuntes/public;
16 index index.html index.php;
17
18 access_log /var/log/nginx/apuntes.access.log;
19 error_log /var/log/nginx/apuntes.error.log;
20
21 location / {
22 try_files $uri $uri/ /index.php?$query_string; # URLs amigables para un front controller
23 }
24
25 location ~ \.php$ {
26 include fastcgi_params;
27 fastcgi_pass unix:/run/php/php8.3-fpm.sock;
28 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
29 }
30
31 location ~ /\. { deny all; } # nada de .env, .git…
32}En Debian y Ubuntu, cada sitio se escribe en sites-available y se activa con un enlace simbólico en sites-enabled. Antes de recargar, comprueba siempre la sintaxis: nginx -t (o apachectl configtest) evita dejar el servidor caído por una llave olvidada. Después, systemctl reload nginx aplica los cambios sin cortar las conexiones abiertas.
1<VirtualHost *:80>
2 ServerName apuntes.es
3 ServerAlias www.apuntes.es
4 DocumentRoot /var/www/apuntes/public
5
6 <Directory /var/www/apuntes/public>
7 AllowOverride All # permite .htaccess (p. ej. las reglas de Laravel)
8 Require all granted
9 </Directory>
10
11 ErrorLog ${APACHE_LOG_DIR}/apuntes.error.log
12 CustomLog ${APACHE_LOG_DIR}/apuntes.access.log combined
13</VirtualHost>
14# a2ensite apuntes.es && a2enmod rewrite && systemctl reload apache23. HTTPS y certificados
HTTPS es HTTP dentro de un canal cifrado con TLS. Protege dos cosas: la confidencialidad (nadie en la red puede leer las contraseñas o las cookies) y la autenticidad (el navegador comprueba que habla con el servidor del dominio y no con un impostor). Esa comprobación se basa en un certificado: un documento que une el dominio con una clave pública, firmado por una autoridad de certificación en la que confían los navegadores.
- El navegador se conecta y el servidor le presenta su certificado.
- El navegador comprueba que está firmado por una autoridad de confianza, que no ha caducado y que es para ese dominio.
- Ambos acuerdan una clave de sesión con criptografía asimétrica y, a partir de ahí, cifran el tráfico con ella.
Hoy no hay excusa para no usar HTTPS: Let's Encrypt emite certificados gratuitos de 90 días y Certbot los solicita y los renueva solo. Un certbot --nginx -d apuntes.es -d www.apuntes.es obtiene el certificado y modifica la configuración; el temporizador de systemd lo renueva antes de que caduque. Aun así, conviene vigilar las fechas de caducidad, como verás en uno de los retos.
4. Seguridad, rendimiento y registros
Cabeceras de seguridad
Unas pocas cabeceras en la respuesta activan protecciones del navegador. No sustituyen a un código seguro, pero cierran puertas a ataques habituales:
1add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # solo HTTPS en adelante
2add_header X-Content-Type-Options "nosniff" always;
3add_header Referrer-Policy "strict-origin-when-cross-origin" always;
4add_header Content-Security-Policy "default-src 'self'; img-src 'self' data:" always;
5server_tokens off; # no anunciar la versiónControl de acceso
Para proteger una zona (un panel de estadísticas, un entorno de pruebas) basta con autenticación básica: un fichero de usuarios creado con htpasswd y las directivas auth_basic en Nginx o AuthType Basic en Apache. También se puede limitar por IP (allow / deny) o, en empresas, autenticar contra el directorio corporativo con LDAP, como verás en el tema de servicios de red.
Rendimiento
| Técnica | Qué consigue | Cómo |
|---|---|---|
| Compresión | Reduce el tamaño de HTML, CSS y JS hasta un 70-80 % | gzip on; (o Brotli) |
| Caché del navegador | Que los ficheros con hash en el nombre no se vuelvan a descargar | expires 1y; o Cache-Control: max-age=31536000, immutable |
| HTTP/2 y HTTP/3 | Varias peticiones por una sola conexión | http2 on; en el bloque server |
| Estáticos desde el servidor web | No ocupar la aplicación con ficheros | Una location para /assets con root y caché |
Los registros cuentan lo que pasa
Cada petición deja una línea en el registro de accesos (quién, cuándo, qué pidió, qué código obtuvo y cuánto ocupó la respuesta) y cada problema, en el registro de errores. Saber leerlos con tail -f, grep y awk es la herramienta de diagnóstico más básica: un aumento de 404 puede indicar un enlace roto o alguien buscando vulnerabilidades; un aumento de 502, que la aplicación se ha caído.
Una línea del registro de Nginx
203.0.113.5 - - [30/Sep/2025:10:01:02 +0200] "GET / HTTP/1.1" 200 5120 "-" "Mozilla/5.0". Con awk, la IP es el campo 1, el método y la ruta están en los campos 6 y 7, y el código de estado en el 9.5. Retos
Dos tareas reales de administración resueltas con Bash: sacar estadísticas de un registro de accesos y generar la configuración de un sitio a partir de sus datos.
Retos de Bash en el IDE
Escribe el script y pulsa Ejecutar tests: se ejecuta en un Linux real con Bash y se prueba con varios casos, algunos ocultos.
La entrada es un fichero de registro de Nginx en formato combinado. Muestra «Peticiones: N», «Errores 4xx: N», «Errores 5xx: N» y «IP con más peticiones: IP (N)». Si hay empate, gana la IP menor alfabéticamente.
La entrada es una línea «dominio raíz [puerto]». Genera el bloque server de Nginx con este formato exacto (4 espacios de sangría): «server {», « listen 80;», « server_name dominio www.dominio;» y, si no hay puerto, « root raíz;» y « index index.html;»; si hay puerto, en su lugar « location / {», « proxy_pass http://127.0.0.1:puerto;», « }». Termina con «}». Si falta el dominio o la raíz, escribe «Uso: dominio raíz [puerto]».