Saltar al contenido

Práctica 8 — Proyecto Final: Servidor Web


LEMP es el acrónimo de:

  • Linux — el sistema operativo (ya lo tienes)
  • Engine-X (nginx) — el servidor web que recibe las peticiones HTTP
  • MariaDB — la base de datos relacional
  • PHP — el lenguaje que genera las páginas dinámicas

Es una de las combinaciones más usadas en servidores web de producción. WordPress, Drupal y muchas aplicaciones corren sobre LEMP.


ventana terminal
# Asegúrate de que el sistema está actualizado
sudo apt update && sudo apt upgrade -y
# Crea los directorios de trabajo
sudo mkdir -p /var/www/misite
sudo mkdir -p /backup/db
# Verifica el estado del firewall (debe estar activo desde la práctica 7)
sudo ufw status

ventana terminal
sudo apt install -y nginx
# Inicia y habilita el servicio
sudo systemctl start nginx
sudo systemctl enable nginx
# Verifica que responde
curl -s -o /dev/null -w "nginx responde: HTTP %{http_code}\n" http://localhost
# Debe devolver: HTTP 200

Si el firewall está activo, permite el tráfico web:

ventana terminal
sudo ufw allow 'Nginx Full'
# Esto abre los puertos 80 (HTTP) y 443 (HTTPS)

ventana terminal
sudo apt install -y mariadb-server
# Inicia y habilita
sudo systemctl start mariadb
sudo systemctl enable mariadb
# Asegurar la instalación: establece contraseña de root, elimina usuarios anónimos
sudo mysql_secure_installation

Durante mysql_secure_installation:

  • Enter current password for root: presiona Enter (no hay contraseña aún)
  • Switch to unix_socket authentication: n
  • Change the root password: y → elige una contraseña segura y anótala
  • Remove anonymous users: y
  • Disallow root login remotely: y
  • Remove test database: y
  • Reload privilege tables: y

Verifica que funciona:

ventana terminal
sudo mysql -u root -p
# Introduce la contraseña que acabas de crear
# Debe aparecer el prompt: MariaDB [(none)]>
exit

Paso 4 — Crear la base de datos y el usuario

Sección titulada “Paso 4 — Crear la base de datos y el usuario"
ventana terminal
sudo mysql -u root -p

En el prompt de MariaDB, ejecuta estos comandos uno a uno:

-- Crea la base de datos
CREATE DATABASE cursodb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- Crea el usuario (pon tu propia contraseña)
CREATE USER 'cursouser'@'localhost' IDENTIFIED BY 'CursoLinux2024!';
-- Concede todos los permisos sobre la base de datos al usuario
GRANT ALL PRIVILEGES ON cursodb.* TO 'cursouser'@'localhost';
-- Aplica los cambios
FLUSH PRIVILEGES;
-- Verifica que la BD existe
SHOW DATABASES;
-- Verifica que el usuario existe
SELECT user, host FROM mysql.user WHERE user = 'cursouser';
exit

Prueba que el usuario puede conectarse:

ventana terminal
mysql -u cursouser -p cursodb
# Introduce la contraseña del usuario cursouser
# Debe aparecer el prompt: MariaDB [cursodb]>
exit

ventana terminal
sudo apt install -y php-fpm php-mysql php-cli
# Verificar la versión instalada y guardarla (la necesitarás después)
php --version
PHP_VERSION=$(php -r "echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;")
echo "Versión PHP: $PHP_VERSION"
# El servicio se llama php8.X-fpm (X varía según la versión)
sudo systemctl start php${PHP_VERSION}-fpm
sudo systemctl enable php${PHP_VERSION}-fpm
systemctl is-active php${PHP_VERSION}-fpm
# Debe decir: active

ventana terminal
sudo nano /var/www/misite/index.php

Escribe:

<?php
// Información del sistema PHP y la conexión a BD
echo "<h1>Servidor Linux — Práctica Final</h1>";
// Información PHP
phpinfo();
?>

Asigna el propietario correcto:

ventana terminal
sudo chown -R www-data:www-data /var/www/misite
sudo chmod -R 755 /var/www/misite

Paso 7 — Configurar el virtualhost de nginx

Sección titulada “Paso 7 — Configurar el virtualhost de nginx"
ventana terminal
sudo nano /etc/nginx/sites-available/misite

Escribe (reemplaza 8.X por tu versión de PHP real, por ejemplo 8.3):

server {
listen 80;
listen [::]:80;
server_name misite.local;
root /var/www/misite;
index index.php index.html;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
}
location ~ /\.ht {
deny all;
}
}

Activa el virtualhost y desactiva el de por defecto:

ventana terminal
# Crea el enlace simbólico para activar el sitio
sudo ln -s /etc/nginx/sites-available/misite /etc/nginx/sites-enabled/
# Desactiva el sitio por defecto (opcional pero recomendado)
sudo rm /etc/nginx/sites-enabled/default
# Verifica que la configuración de nginx es correcta (sin errores de sintaxis)
sudo nginx -t
# Debe decir: syntax is ok / test is successful
# Recarga nginx para aplicar la nueva configuración
sudo systemctl reload nginx

Para que misite.local resuelva a tu servidor sin necesidad de DNS, añádelo al archivo /etc/hosts:

ventana terminal
echo "127.0.0.1 misite.local" | sudo tee -a /etc/hosts
# Verifica que se puede resolver
ping -c 1 misite.local

Prueba que la web responde con PHP:

ventana terminal
curl -s http://misite.local | head -20
# Debe mostrar HTML, incluyendo información de PHP

ventana terminal
# Los tres servicios deben estar activos
for svc in nginx mariadb php8.3-fpm; do
echo "$svc: $(systemctl is-active $svc)"
done
# La web responde con HTTP 200
curl -s -o /dev/null -w "HTTP: %{http_code}\n" http://misite.local
# La BD y el usuario existen
sudo mysql -e "SHOW DATABASES; SELECT user FROM mysql.user WHERE user='cursouser';"

Paso 10 — Backup automático de la base de datos

Sección titulada “Paso 10 — Backup automático de la base de datos"
ventana terminal
# Prueba manual primero
sudo mysqldump -u root cursodb > /backup/db/cursodb_$(date '+%F').sql
# Verifica que el archivo se creó
ls -lh /backup/db/

Automatiza con cron:

ventana terminal
# Edita el crontab del usuario root
sudo crontab -e

Añade esta línea al final (ejecuta a las 2:00 AM todos los días):

0 2 * * * mysqldump -u root cursodb > /backup/db/cursodb_$(date '+\%F').sql

Verifica que el cron está guardado:

ventana terminal
sudo crontab -l

Aplica las medidas de seguridad aprendidas:

ventana terminal
# 1. Verifica UFW (de la práctica 7)
sudo ufw status verbose
# 2. Verifica fail2ban
sudo fail2ban-client status sshd
# 3. Verifica que root no puede conectarse por SSH
grep "PermitRootLogin" /etc/ssh/sshd_config
# 4. Establece permisos correctos en el directorio web
sudo find /var/www/misite -type f -exec chmod 644 {} \;
sudo find /var/www/misite -type d -exec chmod 755 {} \;
sudo chown -R www-data:www-data /var/www/misite

📤 Bloque de entrega (script de corrección)

Sección titulada “📤 Bloque de entrega (script de corrección)"

Ejecuta este script completo. El profesor lo revisará contigo:

#!/bin/bash
echo "=========================================="
echo " ENTREGA PRÁCTICA 8 — PROYECTO FINAL"
echo "=========================================="
echo ""
# Servicios
echo "--- SERVICIOS ---"
for svc in nginx mariadb fail2ban; do
echo "$svc: $(systemctl is-active $svc)"
done
PHP_VER=$(php -r "echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;" 2>/dev/null)
echo "php${PHP_VER}-fpm: $(systemctl is-active php${PHP_VER}-fpm 2>/dev/null)"
echo ""
echo "--- WEB ---"
curl -s -o /dev/null -w "HTTP misite.local: %{http_code}\n" http://misite.local
echo ""
echo "--- BASE DE DATOS ---"
sudo mysql -e "SHOW DATABASES;" 2>/dev/null | grep cursodb && echo "BD cursodb: OK" || echo "BD cursodb: FALTA"
sudo mysql -e "SELECT user FROM mysql.user WHERE user='cursouser';" 2>/dev/null | grep -q cursouser && echo "Usuario cursouser: OK" || echo "Usuario cursouser: FALTA"
echo ""
echo "--- VIRTUALHOST ---"
test -f /etc/nginx/sites-enabled/misite && echo "Virtualhost activo: OK" || echo "Virtualhost activo: FALTA"
test -f /var/www/misite/index.php && echo "index.php: OK" || echo "index.php: FALTA"
echo ""
echo "--- SEGURIDAD ---"
sudo ufw status | grep "Status:"
grep "PermitRootLogin" /etc/ssh/sshd_config
echo ""
echo "--- BACKUP ---"
sudo crontab -l 2>/dev/null | grep mysqldump && echo "Cron backup: OK" || echo "Cron backup: FALTA"
ls -lh /backup/db/ 2>/dev/null | head -5
echo ""
echo "=========================================="

Ejecuta con:

ventana terminal
bash <(cat << 'SCRIPT'
# (pega aquí el script de arriba)
SCRIPT
)

O simplemente ejecuta los comandos uno a uno y copia toda la salida.