Cómo instalar y configurar Apache2 en Debian 13: guía completa para VirtualHosts, PHP, HTTPS y servidores de producción

Apache HTTP Server, conocido comúnmente como Apache2, es uno de los servidores web más utilizados para alojar sitios y aplicaciones web.

Gracias a Apache podemos convertir una computadora con Linux en un servidor capaz de entregar páginas HTML, hojas de estilo CSS, archivos JavaScript, imágenes y otros recursos. Además, mediante tecnologías como PHP-FPM, podemos ejecutar aplicaciones PHP, conectarlas a bases de datos y alojar proyectos más complejos.

Pero instalar Apache2 no significa que nuestro servidor esté preparado para producción.

Para publicar páginas correctamente debemos comprender su funcionamiento, configurar los VirtualHosts, establecer permisos adecuados, habilitar HTTPS, revisar los registros y aplicar medidas de seguridad.

En este tutorial aprenderemos a hacerlo paso a paso utilizando Debian 13, tanto en un entorno local de desarrollo como en un servidor VPS con dominios reales.

1. ¿En qué sistemas operativos podemos utilizar Apache?

Aunque utilizaremos Debian 13, Apache HTTP Server está disponible para diferentes sistemas operativos.

Entre ellos encontramos:

Sistema operativoNombre habitual del paqueteAdministrador de paquetes
Debian 13apache2APT
Debian 12apache2APT
Ubuntu Serverapache2APT
Linux Mintapache2APT
FedorahttpdDNF
Rocky LinuxhttpdDNF
AlmaLinuxhttpdDNF
Arch LinuxapachePacman

También existen versiones para otros sistemas, incluido Windows.

Sin embargo, debemos considerar que las rutas, los nombres de los servicios y la organización de los archivos de configuración pueden cambiar entre distribuciones.

Por ejemplo, en Debian y Ubuntu encontramos habitualmente:

/etc/apache2/

Mientras que en sistemas de la familia Red Hat se utiliza normalmente:

/etc/httpd/

Los comandos de este tutorial están diseñados principalmente para Debian 13 y distribuciones derivadas que mantienen una estructura similar.

2. ¿Qué es Apache2 y cómo funciona?

Apache es un servidor HTTP.

Su función consiste en recibir solicitudes de clientes, generalmente navegadores web, y responder con los recursos correspondientes.

Imaginemos que escribimos en el navegador:

http://localhost

El navegador establece una conexión con el servidor web.

Apache recibe la solicitud, determina qué sitio corresponde al nombre solicitado, busca el recurso y devuelve una respuesta HTTP.

Podemos representar el proceso de esta manera:

NAVEGADOR
   |
   | Solicitud HTTP
   v
APACHE2
   |
   | Busca el VirtualHost correspondiente
   v
DIRECTORIO DEL SITIO
   |
   | Localiza index.html
   v
RESPUESTA HTTP
   |
   v
NAVEGADOR

Si la página contiene HTML, CSS y JavaScript, Apache entrega esos archivos al navegador.

El navegador interpreta el HTML, aplica los estilos CSS y ejecuta el JavaScript correspondiente.

Apache no ejecuta normalmente el JavaScript del navegador. Su función es entregar el archivo para que el cliente lo ejecute.

En cambio, cuando utilizamos PHP, necesitamos un intérprete del lado del servidor.

3. Diferencia entre HTML, CSS, JavaScript y PHP en Apache

Antes de configurar nuestro servidor, conviene comprender cómo se procesa cada tecnología.

Tecnología¿Quién la procesa principalmente?¿Necesita PHP?
HTMLNavegadorNo
CSSNavegadorNo
JavaScript del navegadorNavegadorNo
PHPServidor mediante PHP-FPM u otro controladorSí
ImágenesNavegador, después de recibirlasNo
JSON estáticoAplicación clienteNo

Por ejemplo, una página sencilla puede tener esta estructura:

mi-sitio/
├── index.html
├── css/
│   └── styles.css
├── js/
│   └── script.js
└── imagenes/
    └── portada.webp

Apache puede entregar todos esos archivos sin necesidad de instalar PHP.

Pero si utilizamos:

index.php

Necesitaremos configurar un mecanismo para interpretar el código PHP.

En este tutorial utilizaremos PHP-FPM, una opción adecuada para instalaciones modernas.

4. Instalar Apache2 en Debian 13

Abrimos la terminal y actualizamos la información de los paquetes:

sudo apt update

Después instalamos Apache2:

sudo apt install apache2

Durante la instalación, Debian creará los directorios de configuración, instalará los módulos necesarios y normalmente iniciará el servicio.

Podemos comprobarlo:

systemctl status apache2

Si funciona correctamente, veremos un estado similar a:

Active: active (running)

Iniciar Apache manualmente

sudo systemctl start apache2

Detener Apache

sudo systemctl stop apache2

Reiniciar Apache

sudo systemctl restart apache2

Recargar la configuración

sudo systemctl reload apache2

Habilitar el inicio automático

sudo systemctl enable apache2

También podemos iniciar y habilitar el servicio simultáneamente:

sudo systemctl enable --now apache2

Diferencia entre restart y reload

restart detiene y vuelve a iniciar el servicio.

reload solicita recargar la configuración sin realizar un reinicio completo del servicio.

Cuando modificamos archivos de configuración, generalmente conviene validar primero y después recargar:

sudo apache2ctl configtest
sudo systemctl reload apache2

Si la configuración es correcta, el primer comando debería mostrar:

Syntax OK

5. Comprobar que Apache funciona

Abrimos nuestro navegador y visitamos:

http://localhost

También podemos utilizar:

http://127.0.0.1

Si Apache está funcionando y conserva su sitio predeterminado, veremos la página inicial de Apache para Debian.

Podemos comprobar la respuesta desde la terminal:

curl -I http://localhost

Una respuesta habitual sería:

HTTP/1.1 200 OK

El código 200 indica que la solicitud se procesó correctamente.

Si no funciona, podemos revisar:

sudo systemctl status apache2

Y los registros:

sudo journalctl -u apache2 --since "10 minutes ago"

6. Conocer los directorios de Apache2

En Debian, la configuración principal se encuentra en:

/etc/apache2/

Su estructura habitual es:

/etc/apache2/
├── apache2.conf
├── ports.conf
├── envvars
├── sites-available/
├── sites-enabled/
├── mods-available/
├── mods-enabled/
├── conf-available/
└── conf-enabled/

Veamos para qué sirve cada elemento.

apache2.conf

Es uno de los archivos principales de configuración.

Contiene directivas globales y referencias a otros archivos de configuración.

ports.conf

Define los puertos en los que Apache debe escuchar conexiones.

Normalmente encontraremos el puerto HTTP:

Listen 80

Y, cuando corresponde, configuraciones para HTTPS en el puerto 443.

sites-available

Almacena los archivos de configuración de nuestros sitios web.

Por ejemplo:

/etc/apache2/sites-available/empresa.conf
/etc/apache2/sites-available/tienda.conf

Que un archivo exista aquí no significa que el sitio esté habilitado.

sites-enabled

Contiene enlaces simbólicos a los sitios habilitados.

No necesitamos copiar manualmente los archivos.

Podemos utilizar:

sudo a2ensite empresa.conf

Para deshabilitar:

sudo a2dissite empresa.conf

mods-available y mods-enabled

Almacenan la configuración de módulos disponibles y habilitados.

Por ejemplo, para activar el módulo de reescritura:

sudo a2enmod rewrite

Para desactivarlo:

sudo a2dismod rewrite

conf-available y conf-enabled

Permiten organizar configuraciones adicionales.

Podemos habilitarlas mediante:

sudo a2enconf nombre

Y deshabilitarlas con:

sudo a2disconf nombre

Esta organización facilita administrar diferentes sitios sin colocar toda la configuración en un único archivo.

7. ¿Qué es un VirtualHost?

Un VirtualHost es una configuración que permite a Apache identificar y servir un sitio web específico.

Gracias a los VirtualHosts podemos alojar varias páginas utilizando un mismo servidor y una misma dirección IP.

Por ejemplo:

Servidor Debian
IP: 192.168.1.100
        |
        v
      Apache2
        |
        +--- empresa.test
        |
        +--- tienda.test
        |
        +--- academia.test

Cada dominio puede tener su propio directorio, configuración y archivos de registro.

Apache utiliza información de la solicitud HTTP, como el nombre del host, para seleccionar el VirtualHost correspondiente.

En HTTPS también interviene SNI durante la negociación TLS, que permite seleccionar certificados para diferentes nombres de dominio.

En Apache 2.4 no necesitamos agregar la antigua directiva NameVirtualHost para configurar sitios basados en nombres.

8. Laboratorio local: crear nuestro primer VirtualHost

Vamos a crear una página llamada:

empresa.test

Utilizaremos .test porque es un dominio reservado para pruebas y no necesitamos comprarlo.

Paso 1. Crear el directorio del sitio

Ejecutamos:

sudo mkdir -p /var/www/empresa.test/public

La estructura será:

/var/www/
└── empresa.test/
    └── public/

El directorio public contendrá los archivos que queremos mostrar a los visitantes.

Esta separación resulta especialmente útil cuando más adelante trabajemos con aplicaciones que tienen configuraciones y archivos privados fuera del directorio público.

Paso 2. Crear nuestra primera página HTML

sudo nano /var/www/empresa.test/public/index.html

Agregamos:

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Empresa - Servidor Apache2</title>

    <link rel="stylesheet" href="css/styles.css">
</head>
<body>

    <main>
        <h1>¡Apache2 está funcionando!</h1>

        <p>
            Este sitio utiliza un VirtualHost
            configurado en Debian 13.
        </p>

        <button id="saludar">
            Probar JavaScript
        </button>
    </main>

    <script src="js/script.js"></script>

</body>
</html>

Paso 3. Crear los directorios CSS y JavaScript

sudo mkdir -p /var/www/empresa.test/public/css
sudo mkdir -p /var/www/empresa.test/public/js

Creamos la hoja de estilos:

sudo nano /var/www/empresa.test/public/css/styles.css

Contenido:

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    min-height: 100vh;

    display: grid;
    place-items: center;

    background: #0d1117;
    color: #e6edf3;

    font-family: Arial, sans-serif;
}

main {
    width: min(90%, 600px);
    padding: 40px;

    text-align: center;

    border: 1px solid #00ff41;
    border-radius: 16px;

    background: #161b22;
}

h1 {
    color: #00ff41;
}

button {
    padding: 12px 24px;

    border: none;
    border-radius: 8px;

    background: #00ff41;
    color: #0d1117;

    font-weight: bold;
    cursor: pointer;
}

Ahora creamos JavaScript:

sudo nano /var/www/empresa.test/public/js/script.js

Contenido:

"use strict";

const boton = document.querySelector("#saludar");

boton.addEventListener("click", () => {
    alert("JavaScript funciona correctamente con Apache2.");
});

Con esto tenemos una página HTML que utiliza CSS y JavaScript.

9. Crear el archivo de configuración del VirtualHost

Ahora configuraremos Apache para reconocer nuestro sitio.

Creamos:

sudo nano /etc/apache2/sites-available/empresa.test.conf

Contenido:

<VirtualHost *:80>

    ServerName empresa.test

    DocumentRoot /var/www/empresa.test/public

    <Directory /var/www/empresa.test/public>
        Options -Indexes -FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/empresa.test-error.log

    CustomLog ${APACHE_LOG_DIR}/empresa.test-access.log combined

</VirtualHost>

Vamos a explicar cada directiva.

VirtualHost *:80

<VirtualHost *:80>

Indica que la configuración corresponde a solicitudes HTTP recibidas en el puerto 80, para las direcciones de escucha que coincidan.

ServerName

ServerName empresa.test

Establece el nombre principal del sitio.

Apache utiliza este nombre para identificar el VirtualHost.

DocumentRoot

DocumentRoot /var/www/empresa.test/public

Define el directorio desde el cual se entregarán los archivos públicos.

Directory

<Directory /var/www/empresa.test/public>

Permite establecer reglas aplicables a ese directorio.

Options -Indexes -FollowSymLinks

Options -Indexes -FollowSymLinks

-Indexes evita que Apache genere automáticamente un listado de archivos cuando no encuentra un documento índice y no existe otra configuración que lo permita.

-FollowSymLinks deshabilita el seguimiento de enlaces simbólicos mediante esa opción. Puede ser necesario ajustar esta configuración para aplicaciones que dependen de enlaces simbólicos.

AllowOverride None

AllowOverride None

Impide que los archivos .htaccess sobrescriban la configuración de ese directorio.

Esto mejora el control centralizado y evita la lectura de archivos .htaccess en cada solicitud.

Require all granted

Require all granted

Autoriza el acceso HTTP al contenido de ese directorio, sujeto a otras restricciones que puedan existir.

ErrorLog

ErrorLog ${APACHE_LOG_DIR}/empresa.test-error.log

Establece el archivo donde se registrarán errores del sitio.

CustomLog

CustomLog ${APACHE_LOG_DIR}/empresa.test-access.log combined

Guarda información sobre las solicitudes HTTP recibidas.

El formato combined incluye datos como IP, fecha, recurso solicitado, código de respuesta, referente y agente de usuario.

10. Habilitar nuestro VirtualHost

Ejecutamos:

sudo a2ensite empresa.test.conf

Validamos:

sudo apache2ctl configtest

Si obtenemos:

Syntax OK

Recargamos:

sudo systemctl reload apache2

También podemos deshabilitar el sitio predeterminado de Apache si no lo necesitamos:

sudo a2dissite 000-default.conf

Después validamos y recargamos nuevamente.

Importante: cuando Apache no encuentra un VirtualHost que coincida con el nombre solicitado, puede utilizar el primer VirtualHost correspondiente a esa dirección y puerto. En producción conviene configurar explícitamente el comportamiento para dominios desconocidos.

11. Configurar /etc/hosts para utilizar dominios locales

Hasta ahora creamos el sitio, pero nuestro equipo todavía necesita saber qué dirección IP corresponde a:

empresa.test

Para pruebas locales podemos utilizar:

/etc/hosts

Este archivo permite asociar nombres de host con direcciones IP en el propio equipo.

Lo editamos:

sudo nano /etc/hosts

Agregamos:

127.0.0.1 empresa.test

Guardamos.

Ahora podemos visitar:

http://empresa.test

Nuestro navegador se conectará a la dirección 127.0.0.1, donde Apache recibirá la solicitud y seleccionará el VirtualHost correspondiente.

¿Por qué funciona?

Porque el archivo /etc/hosts proporciona una resolución local del nombre.

El navegador no necesita consultar un servidor DNS público para ese nombre cuando la resolución local tiene prioridad.

¿Otros dispositivos podrán acceder?

No automáticamente.

La dirección:

127.0.0.1

Siempre representa el propio equipo desde el que se utiliza.

Si queremos acceder desde otra computadora de nuestra red, debemos utilizar la dirección privada del servidor, por ejemplo:

192.168.1.100 empresa.test

Esta entrada debe configurarse en el equipo cliente o utilizar un DNS interno.

Además, Apache debe escuchar en una interfaz accesible, el firewall debe permitir las conexiones y la red debe tener conectividad.

12. Alojar una segunda página web en el mismo servidor

Vamos a crear otro sitio:

tienda.test

Primero creamos su directorio:

sudo mkdir -p /var/www/tienda.test/public

Creamos una página sencilla:

sudo nano /var/www/tienda.test/public/index.html

Contenido:

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Mi tienda</title>
</head>
<body>
    <h1>Bienvenido a mi tienda</h1>
    <p>Segundo VirtualHost funcionando.</p>
</body>
</html>

Ahora creamos:

sudo nano /etc/apache2/sites-available/tienda.test.conf

Contenido:

<VirtualHost *:80>

    ServerName tienda.test

    DocumentRoot /var/www/tienda.test/public

    <Directory /var/www/tienda.test/public>
        Options -Indexes -FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/tienda.test-error.log

    CustomLog ${APACHE_LOG_DIR}/tienda.test-access.log combined

</VirtualHost>

Habilitamos:

sudo a2ensite tienda.test.conf

Validamos:

sudo apache2ctl configtest

Recargamos:

sudo systemctl reload apache2

Editamos:

sudo nano /etc/hosts

Agregamos:

127.0.0.1 empresa.test tienda.test

Ahora podemos abrir:

http://empresa.test
http://tienda.test

Ambas páginas funcionan en el mismo servidor Apache, utilizando el mismo puerto 80.

La diferencia está en el nombre solicitado.

Consultar los VirtualHosts activos

Apache incluye un comando muy útil:

sudo apache2ctl -S

Este comando muestra información sobre los VirtualHosts configurados, los nombres asociados y qué sitio funciona como predeterminado.

Es una herramienta fundamental para diagnosticar conflictos entre dominios.

13. Probar VirtualHosts sin modificar /etc/hosts

Existe otra manera de comprobar que Apache reconoce un dominio.

Podemos enviar una solicitud HTTP con un encabezado Host específico:

curl -H "Host: empresa.test" http://127.0.0.1/

Para probar el segundo sitio:

curl -H "Host: tienda.test" http://127.0.0.1/

Esto resulta útil cuando queremos comprobar rápidamente la selección del VirtualHost.

No necesitamos modificar el archivo /etc/hosts para realizar estas pruebas HTTP.

Para HTTPS, donde también importa SNI, conviene utilizar herramientas como curl --resolve, que veremos más adelante.

14. Instalar PHP para ejecutar páginas dinámicas

Hasta ahora Apache puede entregar HTML, CSS y JavaScript.

Ahora vamos a habilitar PHP.

En Debian 13, la versión predeterminada de PHP de sus repositorios oficiales es PHP 8.4.

Para comprobar qué versión ofrece nuestro sistema:

apt policy php-fpm

Instalamos PHP-FPM y algunas extensiones habituales:

sudo apt install php-fpm php-cli php-mysql php-curl php-mbstring php-xml php-zip

No todas las aplicaciones necesitan todas estas extensiones. En producción debemos instalar únicamente las necesarias.

¿Qué es PHP-FPM?

PHP-FPM significa PHP FastCGI Process Manager.

Es un administrador de procesos PHP que permite ejecutar scripts PHP mediante un servicio separado del servidor web.

La comunicación funciona aproximadamente así:

NAVEGADOR
   |
   v
APACHE2
   |
   | Solicitud de archivo PHP
   v
PHP-FPM
   |
   | Interpreta el código PHP
   v
RESULTADO GENERADO
   |
   v
APACHE2
   |
   v
NAVEGADOR

Apache recibe la solicitud y delega la ejecución del archivo PHP a PHP-FPM.

Después entrega la respuesta generada.

Esta separación permite utilizar Apache con el módulo de procesamiento de conexiones mpm_event y administrar los procesos PHP mediante PHP-FPM.

15. Conectar Apache2 con PHP-FPM

Primero verificamos qué versión está instalada:

php -v

También podemos comprobar los archivos de configuración disponibles:

ls /etc/apache2/conf-available/*fpm*

En una instalación habitual de Debian 13 encontraremos:

php8.4-fpm.conf

Activamos los módulos necesarios:

sudo a2enmod proxy_fcgi setenvif

Después habilitamos la configuración de PHP-FPM:

sudo a2enconf php8.4-fpm

Comprobamos el servicio:

systemctl status php8.4-fpm

Si es necesario:

sudo systemctl enable --now php8.4-fpm

Validamos Apache:

sudo apache2ctl configtest

Y reiniciamos:

sudo systemctl restart apache2

Si tenemos instalado y habilitado mod_php con mpm_prefork, debemos revisar esa configuración antes de cambiar a mpm_event, porque los módulos MPM son mutuamente excluyentes.

Para comprobar qué MPM utiliza Apache:

apache2ctl -M | grep mpm

No debemos activar varios MPM simultáneamente.

16. Crear una página PHP de prueba

Vamos a crear:

sudo nano /var/www/empresa.test/public/prueba.php

Contenido:

<?php

declare(strict_types=1);

$fecha = date('Y-m-d H:i:s');

$version = PHP_VERSION;

?>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Prueba PHP</title>
</head>
<body>

    <h1>PHP funciona correctamente</h1>

    <p>
        Fecha del servidor:
        <?= htmlspecialchars($fecha, ENT_QUOTES, 'UTF-8') ?>
    </p>

    <p>
        Versión PHP:
        <?= htmlspecialchars($version, ENT_QUOTES, 'UTF-8') ?>
    </p>

</body>
</html>

Abrimos:

http://empresa.test/prueba.php

Si PHP-FPM está correctamente configurado, veremos el HTML generado por PHP.

El código PHP no debe mostrarse como texto fuente en el navegador.

¿Qué pasa si el navegador descarga el archivo PHP?

Puede indicar que Apache no está enviando el archivo al intérprete PHP.

Debemos revisar la configuración de PHP-FPM antes de publicar el sitio.

Si el servidor expone código fuente PHP, especialmente archivos con credenciales, debemos retirar el sitio de acceso público hasta corregir el problema.

¿Es recomendable utilizar phpinfo()?

phpinfo() es útil para diagnosticar configuraciones, pero revela información detallada sobre PHP y el entorno.

Si creamos una página temporal con esa función, debemos eliminarla después de utilizarla.

17. Configurar DirectoryIndex

Cuando visitamos:

http://empresa.test/

No indicamos directamente qué archivo queremos abrir.

Apache utiliza la directiva DirectoryIndex para determinar qué documentos debe buscar.

Podemos establecerla dentro de nuestro VirtualHost:

DirectoryIndex index.php index.html

Esto indica que Apache buscará primero index.php y después index.html, sujeto a la configuración aplicable.

Es útil para sitios desarrollados con PHP.

En un sitio exclusivamente estático podemos priorizar:

DirectoryIndex index.html

18. Permisos correctos para los archivos web

Uno de los errores más frecuentes al configurar Apache consiste en asignar permisos excesivos.

Por ejemplo:

sudo chmod -R 777 /var/www/

No debemos utilizar este comando como solución general.

Otorgaría permisos de lectura, escritura y ejecución a todos los usuarios sobre una gran cantidad de archivos y directorios.

¿Qué usuario utiliza Apache?

En Debian, Apache suele utilizar el usuario:

www-data

Podemos comprobar los procesos:

ps aux | grep '[a]pache2'

Normalmente veremos un proceso principal con privilegios elevados y procesos trabajadores ejecutándose como www-data.

Permisos habituales

Para archivos web estáticos:

644

Para directorios:

755

Estos valores son comunes, pero no son obligatorios en todos los entornos.

Configurar permisos del laboratorio

Si estamos administrando un sitio cuyos archivos deben permanecer bajo control de root y solo ser leídos por Apache, podemos utilizar:

sudo chown -R root:root /var/www/empresa.test

Después:

sudo find /var/www/empresa.test -type d -exec chmod 755 {} +

Y:

sudo find /var/www/empresa.test -type f -exec chmod 644 {} +

Así, Apache puede leer los archivos públicos sin tener permisos generales para modificarlos.

¿Y si necesitamos editar los archivos como usuario normal?

Podemos organizar la propiedad del proyecto para que una cuenta de despliegue sea propietaria de los archivos.

Por ejemplo, en un entorno de un solo administrador:

sudo chown -R "$USER":www-data /var/www/empresa.test

Sin embargo, esto debe acompañarse de permisos adecuados y una estrategia de despliegue.

No debemos asumir que dar propiedad al grupo www-data es necesario para todos los archivos.

En producción, resulta preferible separar las cuentas que despliegan código de los procesos que lo ejecutan.

¿Qué ocurre con las carpetas de subida?

Las aplicaciones que reciben archivos pueden necesitar directorios escribibles.

Debemos otorgar escritura únicamente sobre esas rutas, no sobre todo el proyecto.

Además, las carpetas de archivos subidos deben protegerse para impedir que los usuarios ejecuten código arbitrario desde ellas.

19. Configurar un dominio real en un VPS

Ahora vamos a pasar del laboratorio local a un entorno de producción.

Supongamos que tenemos:

Dominio: ejemplo.com
VPS: 203.0.113.10

La dirección IP mostrada pertenece a un rango reservado para documentación. Debemos sustituirla por la dirección pública real de nuestro servidor.

Para publicar el sitio necesitamos:

  1. Un servidor con una dirección IP pública o una configuración de red que permita recibir tráfico.
  2. Apache instalado y funcionando.
  3. Un dominio registrado.
  4. Registros DNS que apunten al servidor.
  5. Puertos HTTP y HTTPS accesibles.
  6. Certificados TLS válidos.
  7. Permisos y configuraciones de seguridad adecuados.

Configurar DNS

En el panel DNS del proveedor de nuestro dominio, creamos registros similares a:

Tipo: A
Nombre: @
Valor: 203.0.113.10

Y, si queremos utilizar www:

Tipo: CNAME
Nombre: www
Valor: ejemplo.com

También podríamos utilizar otro registro A para www.

Si existen registros AAAA, deben apuntar a una dirección IPv6 correctamente configurada.

Comprobar la resolución

Podemos utilizar:

dig ejemplo.com

O:

dig +short ejemplo.com A

Para comprobar www:

dig +short www.ejemplo.com

El DNS permite que los clientes encuentren la dirección del servidor.

El DNS no crea el VirtualHost: únicamente ayuda a dirigir la conexión hacia la máquina correspondiente.

20. Crear el VirtualHost del dominio real

Creamos el directorio:

sudo mkdir -p /var/www/ejemplo.com/public

Creamos la página inicial:

sudo nano /var/www/ejemplo.com/public/index.html

Contenido:

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Mi sitio en producción</title>
</head>
<body>
    <h1>Bienvenido a ejemplo.com</h1>
    <p>Servidor Apache2 en Debian 13.</p>
</body>
</html>

Ahora creamos el VirtualHost:

sudo nano /etc/apache2/sites-available/ejemplo.com.conf

Contenido:

<VirtualHost *:80>

    ServerName ejemplo.com
    ServerAlias www.ejemplo.com

    ServerAdmin [email protected]

    DocumentRoot /var/www/ejemplo.com/public

    <Directory /var/www/ejemplo.com/public>
        Options -Indexes -FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/ejemplo.com-error.log

    CustomLog ${APACHE_LOG_DIR}/ejemplo.com-access.log combined

</VirtualHost>

Debemos sustituir el dominio y el correo administrativo por valores reales.

Habilitamos:

sudo a2ensite ejemplo.com.conf

Validamos:

sudo apache2ctl configtest

Recargamos:

sudo systemctl reload apache2

¿Qué es ServerAlias?

Esta directiva permite asociar nombres adicionales al mismo VirtualHost.

Por ejemplo:

ServerAlias www.ejemplo.com

Permite que el sitio responda también a solicitudes dirigidas a www.ejemplo.com.

No crea automáticamente el registro DNS ni el certificado HTTPS correspondiente.

21. Configurar el firewall

En un servidor de producción debemos controlar los puertos accesibles.

Apache utiliza habitualmente:

80  = HTTP
443 = HTTPS

Podemos utilizar UFW si forma parte de nuestra estrategia de firewall.

Instalamos:

sudo apt install ufw

Antes de activarlo en un VPS remoto, debemos permitir SSH.

Si utilizamos el puerto SSH habitual:

sudo ufw allow 22/tcp

Si utilizamos otro puerto, debemos permitir el puerto real antes de habilitar el firewall.

Después permitimos HTTP y HTTPS:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Podemos comprobar las reglas:

sudo ufw status verbose

Y habilitarlo:

sudo ufw enable

Advertencia: una configuración incorrecta del firewall puede bloquear nuestra conexión SSH y dejarnos sin acceso remoto.

También debemos comprobar las reglas del proveedor del VPS, porque algunos servicios utilizan firewalls adicionales fuera del sistema operativo.

22. Configurar HTTPS con Let’s Encrypt

En producción debemos utilizar HTTPS para proteger la comunicación entre el navegador y el servidor.

HTTPS utiliza TLS para cifrar las conexiones y autenticar el servidor mediante certificados digitales.

Una opción ampliamente utilizada para obtener certificados es Let’s Encrypt.

Podemos administrar estos certificados con Certbot.

Instalar Certbot

En Debian:

sudo apt install certbot python3-certbot-apache

Antes de continuar, debemos comprobar que:

  • El dominio apunta al servidor correcto.
  • Apache responde por HTTP.
  • El puerto 80 está accesible desde Internet.
  • Los VirtualHosts están configurados correctamente.

Solicitar el certificado

sudo certbot --apache -d ejemplo.com -d www.ejemplo.com

Certbot intentará validar el control de ambos nombres y configurar el certificado en Apache.

Si uno de los nombres no está configurado correctamente en DNS, la validación puede fallar.

Durante el proceso, Certbot puede ofrecer opciones relacionadas con la redirección de HTTP a HTTPS.

Después podremos visitar:

https://ejemplo.com

Comprobar la renovación

Los certificados tienen una vigencia limitada.

Certbot suele instalar un mecanismo de renovación automática mediante systemd o cron, según el paquete y el entorno.

Podemos realizar una prueba:

sudo certbot renew --dry-run

También conviene comprobar qué temporizador está disponible:

systemctl list-timers | grep certbot

La renovación debe verificarse periódicamente, especialmente después de cambios en DNS, firewall o configuración del servidor.

23. Comprender un VirtualHost HTTPS

Una configuración HTTPS utiliza normalmente el puerto 443.

Un ejemplo conceptual sería:

<VirtualHost *:443>

    ServerName ejemplo.com
    ServerAlias www.ejemplo.com

    DocumentRoot /var/www/ejemplo.com/public

    SSLEngine on

    SSLCertificateFile /etc/letsencrypt/live/ejemplo.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ejemplo.com/privkey.pem

    <Directory /var/www/ejemplo.com/public>
        Options -Indexes -FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/ejemplo.com-ssl-error.log
    CustomLog ${APACHE_LOG_DIR}/ejemplo.com-ssl-access.log combined

</VirtualHost>

Este bloque es ilustrativo: no debemos activarlo antes de que existan los certificados correspondientes y el módulo SSL esté habilitado.

Cuando utilizamos Certbot con el complemento de Apache, normalmente puede generar y administrar parte de esta configuración automáticamente.

SSLEngine on

Activa TLS para ese VirtualHost.

SSLCertificateFile

Indica la ubicación del certificado y su cadena.

SSLCertificateKeyFile

Indica la ubicación de la clave privada.

La clave privada nunca debe colocarse dentro del directorio público del sitio.

Tampoco debemos modificar indiscriminadamente los permisos de /etc/letsencrypt.

24. Configuraciones básicas de seguridad en Apache2

La seguridad de Apache depende de varias capas: configuración del servidor, sistema operativo, permisos, aplicaciones, actualizaciones y controles de red.

No existe una sola directiva que convierta automáticamente un servidor en seguro.

Ocultar información innecesaria del servidor

Podemos crear una configuración global:

sudo nano /etc/apache2/conf-available/seguridad-oplinux.conf

Contenido:

ServerTokens Prod
ServerSignature Off
TraceEnable Off

ServerTokens Prod

Reduce la información de versión que Apache anuncia en determinadas respuestas HTTP.

ServerSignature Off

Deshabilita la firma del servidor en páginas generadas por Apache, como algunas respuestas de error.

TraceEnable Off

Deshabilita el método HTTP TRACE.

Estas medidas reducen información expuesta, pero no sustituyen las actualizaciones ni corrigen vulnerabilidades.

Habilitamos:

sudo a2enconf seguridad-oplinux

Validamos:

sudo apache2ctl configtest

Y recargamos:

sudo systemctl reload apache2

25. Evitar el listado de directorios

Supongamos que tenemos:

/var/www/ejemplo.com/public/imagenes/

Y ese directorio no contiene un archivo índice.

Si Apache permite generar índices, podría mostrar un listado de sus archivos.

Para evitarlo utilizamos:

Options -Indexes

Podemos establecer esta opción dentro del bloque <Directory> de cada VirtualHost.

Esto evita la generación automática del listado, pero no convierte los archivos públicos en privados.

Si alguien conoce la URL de un archivo accesible, podría seguir solicitándolo directamente.

Los archivos confidenciales deben permanecer fuera del DocumentRoot o estar protegidos mediante reglas de acceso apropiadas.

26. Proteger archivos sensibles

Las aplicaciones pueden contener archivos como:

.env
.git/
composer.json
composer.lock
config.php
backup.sql

No todos estos archivos tienen la misma sensibilidad, pero varios pueden revelar información importante.

La primera medida es diseñar correctamente el directorio público.

Por ejemplo, en una aplicación Laravel, el DocumentRoot debe apuntar al directorio:

public/

No a la raíz completa del proyecto.

Además, podemos agregar reglas complementarias.

Por ejemplo, dentro de un VirtualHost:

<FilesMatch "^\.">
    Require all denied
</FilesMatch>

Esta regla deniega archivos cuyo nombre comienza con punto dentro del alcance correspondiente.

Debemos tener cuidado con aplicaciones que necesiten servir determinados recursos bajo rutas especiales.

Para proteger archivos con extensiones sensibles, podemos utilizar una regla adicional adaptada al proyecto:

<FilesMatch "\.(?:bak|old|sql|ini|log)$">
    Require all denied
</FilesMatch>

Estas reglas son defensas complementarias, no una garantía de que todos los secretos estén protegidos.

La solución principal sigue siendo no colocar información privada dentro del directorio público.

27. Cabeceras HTTP de seguridad

Apache permite configurar cabeceras HTTP mediante mod_headers.

Habilitamos:

sudo a2enmod headers

Después podemos incorporar determinadas cabeceras al VirtualHost.

Ejemplo:

Header always set X-Content-Type-Options "nosniff"

Header always set Referrer-Policy "strict-origin-when-cross-origin"

Header always set X-Frame-Options "SAMEORIGIN"

X-Content-Type-Options

Con nosniff, indica a los navegadores que respeten los tipos MIME en los contextos donde se aplica esta protección.

Referrer-Policy

Controla qué información de referencia puede compartir el navegador al navegar hacia otros recursos.

X-Frame-Options

Con SAMEORIGIN, restringe determinados usos del sitio dentro de marcos de otros orígenes.

Debemos comprobar la compatibilidad de estas cabeceras con nuestra aplicación.

Por ejemplo, un sitio que necesita integrarse mediante iframes puede requerir una política diferente.

¿Qué sucede con HSTS?

HSTS permite indicar a los navegadores que deben utilizar HTTPS para un dominio durante un periodo determinado.

Ejemplo:

Header always set Strict-Transport-Security "max-age=31536000"

Pero solo debe habilitarse después de comprobar que HTTPS funciona correctamente y que estamos preparados para mantenerlo.

No debemos activar includeSubDomains sin verificar todos los subdominios.

¿Y Content-Security-Policy?

CSP es una protección importante contra determinadas clases de inyección de contenido.

Sin embargo, no existe una política universal que funcione correctamente para todos los sitios.

Debe diseñarse según los scripts, estilos, imágenes, fuentes y servicios externos que utiliza cada aplicación.

Copiar una CSP restrictiva sin probarla puede romper funcionalidades legítimas.

28. ¿Qué es mod_rewrite y para qué sirve?

mod_rewrite permite aplicar reglas de reescritura de URL.

Es utilizado por aplicaciones y gestores de contenido para trabajar con rutas amigables.

Por ejemplo:

https://ejemplo.com/productos

En lugar de:

https://ejemplo.com/index.php?pagina=productos

Habilitamos el módulo:

sudo a2enmod rewrite

Validamos y recargamos Apache.

¿Es obligatorio utilizar .htaccess?

No.

Las reglas pueden establecerse directamente en los archivos de configuración de Apache.

Esto suele ser preferible cuando administramos el servidor.

Sin embargo, aplicaciones como WordPress utilizan frecuentemente .htaccess para sus reglas de enlaces permanentes.

En esos casos podemos permitir las categorías de directivas necesarias mediante AllowOverride, por ejemplo:

<Directory /var/www/wordpress/public>
    Options -Indexes -FollowSymLinks
    AllowOverride FileInfo
    Require all granted
</Directory>

Este ejemplo permite determinadas directivas relacionadas con el procesamiento de solicitudes y reescrituras.

La configuración concreta debe adaptarse a la aplicación.

No conviene utilizar AllowOverride All indiscriminadamente cuando podemos limitar las directivas necesarias.

29. Configurar Apache para WordPress

WordPress utiliza PHP y normalmente una base de datos MySQL o MariaDB.

Apache puede alojarlo mediante un VirtualHost convencional.

Por ejemplo:

<VirtualHost *:80>

    ServerName blog.ejemplo.com

    DocumentRoot /var/www/blog.ejemplo.com/public

    DirectoryIndex index.php index.html

    <Directory /var/www/blog.ejemplo.com/public>
        Options -Indexes -FollowSymLinks
        AllowOverride FileInfo
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/blog-error.log

    CustomLog ${APACHE_LOG_DIR}/blog-access.log combined

</VirtualHost>

Además, necesitaremos instalar WordPress, configurar la base de datos, establecer permisos adecuados y habilitar HTTPS.

¿Qué sucede con wp-config.php?

Contiene información sensible de configuración.

No debemos publicarlo como archivo de texto ni permitir que Apache entregue su código fuente.

Una configuración correcta de PHP es fundamental.

También debemos mantener WordPress, sus temas y plugins actualizados.

30. Configurar Apache para Laravel

Laravel utiliza una estructura diferente a la de un sitio PHP tradicional.

Un proyecto puede contener:

mi-proyecto/
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── resources/
├── routes/
├── storage/
└── vendor/

El directorio público es:

public/

Por eso, el VirtualHost debe apuntar allí:

DocumentRoot /var/www/mi-proyecto/public

Ejemplo:

<VirtualHost *:80>

    ServerName laravel.test

    DocumentRoot /var/www/mi-proyecto/public

    <Directory /var/www/mi-proyecto/public>
        Options -Indexes -FollowSymLinks
        AllowOverride None
        Require all granted

        FallbackResource /index.php
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/laravel-error.log

    CustomLog ${APACHE_LOG_DIR}/laravel-access.log combined

</VirtualHost>

FallbackResource permite dirigir solicitudes que no corresponden a archivos existentes hacia el controlador frontal de Laravel, siempre que la aplicación y el resto de la configuración sean compatibles.

Es una alternativa a determinadas reglas de reescritura.

Permisos especiales en Laravel

Laravel necesita escribir en algunos directorios, especialmente:

storage/
bootstrap/cache/

Debemos conceder escritura al usuario o grupo que ejecuta PHP-FPM únicamente donde sea necesario.

No debemos aplicar 777 a todo el proyecto.

También debemos configurar correctamente:

APP_ENV=production
APP_DEBUG=false

En producción, los mensajes detallados de depuración no deben exponerse a los visitantes.

31. Alojar varios sitios PHP: una consideración de seguridad

Cuando alojamos varios proyectos PHP en el mismo servidor, es importante considerar el aislamiento entre ellos.

En una configuración básica, todos pueden ejecutarse mediante un mismo pool PHP-FPM y una misma identidad del sistema, como www-data.

Esto significa que una aplicación vulnerable podría tener acceso a archivos de otra aplicación si los permisos del sistema lo permiten.

Para entornos con múltiples proyectos independientes podemos configurar pools PHP-FPM separados, con usuarios y grupos específicos.

Por ejemplo:

Sitio A
   |
   v
Pool PHP-FPM A
Usuario: sitio-a

Sitio B
   |
   v
Pool PHP-FPM B
Usuario: sitio-b

Esto permite establecer límites y permisos diferenciados.

Sin embargo, requiere una configuración adicional de sockets, usuarios, propietarios y VirtualHosts.

Tener varios VirtualHosts no significa que los sitios estén aislados entre sí.

Para alojamientos de múltiples clientes, debemos considerar controles de aislamiento más sólidos, actualizaciones, políticas de acceso y, cuando corresponda, contenedores o máquinas virtuales independientes.

32. Consultar los registros de Apache

Los registros son fundamentales para detectar errores y analizar solicitudes.

En Debian suelen almacenarse en:

/var/log/apache2/

Podemos consultar los errores generales:

sudo tail -f /var/log/apache2/error.log

O los de nuestro sitio:

sudo tail -f /var/log/apache2/empresa.test-error.log

Para revisar las solicitudes:

sudo tail -f /var/log/apache2/empresa.test-access.log

Códigos HTTP importantes

CódigoSignificado
200Solicitud correcta
301Redirección permanente
302Redirección temporal
403Acceso prohibido
404Recurso no encontrado
500Error interno del servidor
502Respuesta incorrecta de un servidor intermediario
503Servicio no disponible

Si una página PHP devuelve un error 500, debemos revisar tanto los registros de Apache como los de PHP-FPM y la propia aplicación.

Consultar PHP-FPM

sudo journalctl -u php8.4-fpm --since "15 minutes ago"

Esto puede ayudarnos a detectar problemas de ejecución, configuración o permisos.

33. Diagnosticar errores comunes

Error: Apache no inicia

Primero ejecutamos:

sudo apache2ctl configtest

Después:

sudo systemctl status apache2

Y revisamos:

sudo journalctl -u apache2 -n 50 --no-pager

Error: el puerto 80 está ocupado

Podemos consultar qué proceso lo utiliza:

sudo ss -ltnp '( sport = :80 )'

Puede existir otro servidor web, un contenedor Docker o una instancia previa utilizando ese puerto.

Error: aparece la página predeterminada de Apache

Revisamos:

sudo apache2ctl -S

También comprobamos:

ls -l /etc/apache2/sites-enabled/

El problema puede estar relacionado con el VirtualHost predeterminado o con un nombre de host que no coincide.

Error: 403 Forbidden

Debemos revisar:

  • Permisos del archivo.
  • Permisos de los directorios superiores.
  • Directivas <Directory>.
  • Reglas Require.
  • ACL y otras restricciones.

Un comando útil es:

namei -l /var/www/empresa.test/public/index.html

Error: 404 Not Found

Comprobamos que el archivo exista dentro del DocumentRoot correcto.

También revisamos reglas de reescritura y rutas de la aplicación.

Error: PHP no funciona

Revisamos:

systemctl status php8.4-fpm

Después:

apache2ctl -M | grep proxy

Y comprobamos que la configuración PHP-FPM esté habilitada.

Error: el dominio funciona localmente, pero no desde Internet

Debemos comprobar:

  • DNS público.
  • IP del servidor.
  • Firewall del sistema.
  • Firewall del proveedor.
  • Puertos de escucha.
  • Configuración del VirtualHost.
  • Conectividad desde el exterior.

34. Comprobar un dominio antes de cambiar el DNS

Cuando migramos un sitio web a otro servidor, podemos probarlo antes de modificar los registros públicos.

Por ejemplo:

curl --resolve ejemplo.com:80:203.0.113.10 http://ejemplo.com/

Esto hace que curl utilice la dirección indicada para esa solicitud, manteniendo el nombre del dominio.

Para HTTPS:

curl --resolve ejemplo.com:443:203.0.113.10 https://ejemplo.com/

En HTTPS, el certificado debe ser válido para el nombre solicitado.

Esta técnica es especialmente útil durante migraciones y pruebas de nuevos servidores.

35. Mejorar el rendimiento de Apache

Apache utiliza módulos de multiprocesamiento conocidos como MPM.

Entre ellos encontramos:

  • mpm_event
  • mpm_worker
  • mpm_prefork

Para comprobar cuál está activo:

apache2ctl -M | grep mpm

En instalaciones modernas que utilizan PHP-FPM, mpm_event suele ser una buena elección.

Sin embargo, el rendimiento depende de la memoria disponible, el número de conexiones, las aplicaciones, PHP-FPM, la base de datos y otros factores.

Consultar la configuración de módulos

apache2ctl -M

No debemos activar módulos innecesarios.

Ajustar MaxRequestWorkers

Esta directiva limita el número de solicitudes que pueden procesarse simultáneamente según el MPM utilizado.

No existe un valor universal adecuado para todos los servidores.

Debemos medir el consumo de memoria y la carga real antes de modificarlo.

Compresión y caché

Apache dispone de módulos para compresión y políticas de caché.

Por ejemplo:

sudo a2enmod deflate expires

Sin embargo, debemos diseñar cuidadosamente las reglas de caché.

No conviene almacenar en caché respuestas privadas, contenido personalizado o páginas dinámicas sin considerar sus encabezados y comportamiento.

La optimización debe basarse en pruebas, no en activar todas las funciones disponibles.

36. Mantener Apache actualizado

En producción debemos mantener actualizados Apache, PHP, el sistema operativo y las aplicaciones alojadas.

Podemos consultar los paquetes pendientes:

apt list --upgradable

Para instalar actualizaciones:

sudo apt update
sudo apt upgrade

En servidores de producción conviene planificar las actualizaciones, revisar cambios relevantes y mantener respaldos verificables.

También podemos considerar unattended-upgrades para determinadas actualizaciones automáticas de seguridad, con una política de reinicios y supervisión apropiada.

37. Lista de comprobación antes de publicar un servidor

Antes de considerar que nuestro Apache está preparado para producción, debemos revisar:

  • Apache inicia correctamente y su configuración supera apache2ctl configtest.
  • Cada dominio tiene su VirtualHost correspondiente.
  • Los registros DNS apuntan al servidor correcto.
  • Los puertos 80 y 443 están configurados y protegidos.
  • HTTPS funciona y los certificados pueden renovarse.
  • Los archivos privados están fuera del DocumentRoot.
  • Los directorios públicos no permiten escritura innecesaria.
  • PHP-FPM funciona y utiliza una versión mantenida.
  • Los mensajes de depuración no están expuestos.
  • Los módulos innecesarios están deshabilitados.
  • Los registros se almacenan y se revisan.
  • Los respaldos existen y se han probado.
  • El sistema operativo recibe actualizaciones.
  • Existe un procedimiento de recuperación ante fallas.
  • Las aplicaciones están actualizadas y configuradas de forma segura.

Estas comprobaciones reducen riesgos, pero no sustituyen una auditoría de seguridad ni garantizan que un servidor esté libre de vulnerabilidades.

38. Resumen de comandos fundamentales

ComandoFunción
sudo apt install apache2Instalar Apache
systemctl status apache2Consultar el servicio
sudo systemctl restart apache2Reiniciar Apache
sudo systemctl reload apache2Recargar configuración
sudo apache2ctl configtestValidar configuración
sudo apache2ctl -SConsultar VirtualHosts
sudo a2ensite sitio.confHabilitar un sitio
sudo a2dissite sitio.confDeshabilitar un sitio
sudo a2enmod rewriteHabilitar reescritura
sudo a2enmod headersHabilitar cabeceras
sudo a2enconf configuracionHabilitar configuración adicional
apache2ctl -MMostrar módulos cargados
sudo tail -f /var/log/apache2/error.logSeguir registros de errores

39. Conclusión

Apache2 es mucho más que un programa para mostrar páginas HTML.

Es una herramienta que permite construir y administrar servidores web capaces de alojar múltiples sitios, ejecutar aplicaciones PHP, trabajar con dominios reales y ofrecer conexiones HTTPS.

Durante este tutorial aprendimos a instalar Apache2 en Debian 13, comprender sus directorios de configuración, crear VirtualHosts, utilizar dominios locales mediante /etc/hosts, publicar sitios con DNS real y configurar PHP-FPM.

También revisamos medidas fundamentales de seguridad, permisos, certificados, registros y mantenimiento.

La idea principal es comprender que un servidor web correctamente configurado no depende únicamente de Apache, sino de la combinación de varios elementos:

SISTEMA OPERATIVO
       |
       v
RED Y FIREWALL
       |
       v
DNS Y DOMINIOS
       |
       v
APACHE2
       |
       +--- HTML / CSS / JavaScript
       |
       +--- PHP-FPM
       |       |
       |       +--- Aplicaciones PHP
       |       +--- WordPress
       |       +--- Laravel
       |
       +--- HTTPS / TLS
       |
       +--- REGISTROS Y SEGURIDAD

Dominar estas herramientas es un paso importante para administrar servidores Linux, desarrollar aplicaciones web y comprender cómo funcionan los servicios de alojamiento.

Lo recomendable es comenzar en un entorno local, practicar con varios VirtualHosts y después trasladar esos conocimientos a un VPS de pruebas antes de publicar aplicaciones reales.


OPERSLINUX — Aprende Linux comprendiendo cómo funciona.

La administración de servidores se aprende practicando, investigando los errores y entendiendo la función de cada configuración, no simplemente copiando comandos.

Deja un comentario