--- title: "Cómo usar .htaccess en Apache en Ubuntu 24.04" description: "Activa .htaccess en Apache en Ubuntu 24.04 y úsalo para forzar HTTPS, crear redirecciones y URL limpias, proteger directorios con clave y gestionar la caché." category: "Servidores Web" language: es source: https://cubepath.com/es/docs/servidores-web/configuracion-de-htaccess-en-apache updated: 2026-09-25 --- # Cómo usar .htaccess en Apache en Ubuntu 24.04 Un archivo `.htaccess` contiene directivas de Apache que se aplican al directorio donde está y a todos sus subdirectorios. Apache lo lee en cada petición, así que los cambios tienen efecto al instante, sin recargar el servidor. Es la forma habitual de configurar redirecciones y reglas de reescritura en hostings compartidos y en aplicaciones como WordPress. En este tutorial activarás `.htaccess` en Apache sobre Ubuntu 24.04 y lo usarás para las tareas más comunes: redirecciones, HTTPS obligatorio, URL limpias, protección con contraseña y cabeceras de caché y seguridad. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, y un usuario no root con privilegios `sudo`. - Apache instalado (`sudo apt install apache2`) con un sitio cuyo `DocumentRoot` sea `/var/www/your_domain`. Sustituye `your_domain` por tu dominio en toda la guía. - Para las reglas de HTTPS, un certificado TLS ya instalado en el sitio, por ejemplo de Let's Encrypt. > Nota: si administras el servidor, las mismas directivas son más eficientes dentro del VirtualHost, porque Apache las lee una sola vez al arrancar en lugar de buscar archivos `.htaccess` en cada directorio y en cada petición. Usa `.htaccess` cuando la aplicación lo requiera, cuando otras personas deban cambiar reglas sin acceso root o en hostings compartidos. ## Paso 1: Permitir .htaccess en el sitio Apache solo lee `.htaccess` en los directorios donde `AllowOverride` lo permite. En Ubuntu, `/etc/apache2/apache2.conf` define `AllowOverride None` para `/var/www/`, así que por defecto los archivos `.htaccess` se ignoran sin ningún aviso. Abre el VirtualHost de tu sitio: ```bash sudo nano /etc/apache2/sites-available/your_domain.conf ``` Añade un bloque `` para el `DocumentRoot` dentro de `` (y dentro de `` si tienes un archivo aparte para HTTPS, por ejemplo `your_domain-le-ssl.conf` creado por Certbot): ```apache ServerName your_domain ServerAlias www.your_domain DocumentRoot /var/www/your_domain AllowOverride All Require all granted ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined ``` `AllowOverride All` permite cualquier directiva válida en `.htaccess`. Si quieres restringirlo, indica solo las categorías que usa esta guía: `AllowOverride FileInfo AuthConfig Indexes Options`. `FileInfo` cubre reescrituras, redirecciones, cabeceras y páginas de error; `AuthConfig`, la autenticación y `Require`; `Indexes`, las directivas de caché de `mod_expires`, y `Options`, la directiva `Options`. ## Paso 2: Activar los módulos necesarios Las reglas de esta guía usan `mod_rewrite` para reescrituras, `mod_headers` para cabeceras y `mod_expires` para la caché del navegador. En Ubuntu vienen instalados pero no habilitados: ```bash sudo a2enmod rewrite headers expires ``` Valida la configuración y reinicia Apache para cargar los módulos: ```bash sudo apache2ctl configtest sudo systemctl restart apache2 ``` ```output Syntax OK ``` Comprueba que están cargados: ```bash sudo apache2ctl -M | grep -E 'rewrite|headers|expires' ``` ```output expires_module (shared) headers_module (shared) rewrite_module (shared) ``` ## Paso 3: Comprobar que Apache lee .htaccess Crea el archivo en la raíz del sitio con una línea deliberadamente inválida: ```bash echo "EstaDirectivaNoExiste" | sudo tee /var/www/your_domain/.htaccess ``` Pide la página: ```bash curl -sI http://your_domain | head -n 1 ``` ```output HTTP/1.1 500 Internal Server Error ``` Un error 500 confirma que Apache lee el archivo. El log de errores muestra la causa: ```bash sudo tail -n 1 /var/log/apache2/error.log ``` ```output [core:alert] ... /var/www/your_domain/.htaccess: Invalid command 'EstaDirectivaNoExiste', perhaps misspelled or defined by a module not included in the server configuration ``` Si la respuesta es `200 OK`, `AllowOverride` no se está aplicando: revisa el paso 1 y que editaste el VirtualHost correcto (`sudo apache2ctl -S` lista los sitios activos). Esta misma técnica te servirá para depurar: cualquier error de sintaxis en `.htaccess` produce un 500 y deja el motivo en el log. Vacía el archivo para empezar a añadir reglas reales: ```bash sudo truncate -s 0 /var/www/your_domain/.htaccess ``` Todas las reglas siguientes van en `/var/www/your_domain/.htaccess`. Ábrelo con: ```bash sudo nano /var/www/your_domain/.htaccess ``` ## Paso 4: Forzar HTTPS y un único nombre de dominio Conviene que el sitio responda en una sola dirección canónica, por ejemplo `https://your_domain` sin `www`. Añade al principio del archivo: ```apache RewriteEngine On # Redirigir www a la versión sin www, ya por HTTPS RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] RewriteRule ^ https://%1%{REQUEST_URI} [L,R=301] # Redirigir HTTP a HTTPS RewriteCond %{HTTPS} off RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] ``` Cómo funciona: - `RewriteCond` define una condición que debe cumplirse para aplicar la `RewriteRule` que la sigue. `%1` es lo capturado entre paréntesis en la condición, es decir, el dominio sin `www.`. - `^` en `RewriteRule` coincide con cualquier ruta; `%{REQUEST_URI}` conserva la ruta y la consulta original. - `R=301` genera una redirección permanente y `L` detiene el procesamiento de las reglas siguientes. Si el sitio está detrás de un balanceador o un proxy que termina TLS, Apache recibe siempre HTTP y la condición `%{HTTPS} off` crea un bucle de redirecciones. En ese caso usa la cabecera que envía el proxy: ```apache RewriteCond %{HTTP:X-Forwarded-Proto} !https RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] ``` Guarda el archivo y comprueba las redirecciones: ```bash curl -sI http://www.your_domain/contacto | grep -E '^(HTTP|Location)' ``` ```output HTTP/1.1 301 Moved Permanently Location: https://your_domain/contacto ``` > Consejo: mientras pruebes reglas nuevas usa `R=302`. Los navegadores guardan en caché las redirecciones 301 y seguirán aplicando una regla errónea aunque la corrijas. Cambia a `301` cuando todo funcione. ## Paso 5: Redirigir páginas movidas Para redirecciones fijas de una URL a otra no necesitas `mod_rewrite`: la directiva `Redirect` de `mod_alias`, habilitado por defecto, es más simple. Añade al archivo: ```apache Redirect 301 /pagina-antigua.html /pagina-nueva/ Redirect 301 /blog/ https://blog.your_domain/ ``` La segunda línea redirige también todo lo que cuelga de `/blog/`, conservando el resto de la ruta: `/blog/post-1` va a `https://blog.your_domain/post-1`. Para patrones, usa `RedirectMatch` con una expresión regular: ```apache RedirectMatch 301 ^/productos/([0-9]+)\.html$ /tienda/producto/$1 ``` Compruébalo: ```bash curl -sI https://your_domain/pagina-antigua.html | grep -E '^(HTTP|Location)' ``` ```output HTTP/1.1 301 Moved Permanently Location: https://your_domain/pagina-nueva/ ``` ## Paso 6: Crear URL limpias Estas reglas permiten acceder a `acerca.html` como `/acerca`, sin extensión, y dirigen al `index.php` de la aplicación todas las rutas que no correspondan a un archivo o directorio real (el patrón de controlador frontal que usan WordPress, Laravel y la mayoría de frameworks PHP). Añádelas después de las reglas del paso 4: ```apache # Servir /acerca desde acerca.html si existe RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}.html -f RewriteRule ^(.+)$ $1.html [L] # Enviar el resto de rutas inexistentes a index.php RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.php [L] ``` `-f` comprueba que existe un archivo y `-d` un directorio. Sin la bandera `R`, la reescritura es interna: el navegador sigue viendo `/acerca` en la barra de direcciones. Usa solo el segundo bloque si tu aplicación es PHP, o solo el primero si es un sitio HTML estático. Crea una página de prueba y compruébala: ```bash echo "

Acerca de

" | sudo tee /var/www/your_domain/acerca.html curl -s https://your_domain/acerca ``` ```output

Acerca de

``` ## Paso 7: Proteger un directorio con contraseña La autenticación básica de Apache es útil para proteger un área de administración o un entorno de pruebas. Instala `htpasswd`, incluido en el paquete `apache2-utils`: ```bash sudo apt install apache2-utils ``` Crea el archivo de contraseñas fuera del `DocumentRoot`, para que nunca se pueda descargar desde la web. La opción `-c` crea el archivo y solo debe usarse con el primer usuario; te pedirá la contraseña: ```bash sudo htpasswd -c /etc/apache2/.htpasswd your_user ``` Apache debe poder leerlo, pero nadie más: ```bash sudo chown root:www-data /etc/apache2/.htpasswd sudo chmod 640 /etc/apache2/.htpasswd ``` Crea un `.htaccess` en el directorio que quieras proteger, por ejemplo `/var/www/your_domain/admin`: ```bash sudo mkdir -p /var/www/your_domain/admin sudo nano /var/www/your_domain/admin/.htaccess ``` ```apache AuthType Basic AuthName "Zona restringida" AuthUserFile /etc/apache2/.htpasswd Require valid-user ``` Comprueba que sin credenciales se deniega el acceso y con ellas se permite: ```bash curl -sI https://your_domain/admin/ | head -n 1 curl -sI -u your_user https://your_domain/admin/ | head -n 1 ``` ```output HTTP/1.1 401 Unauthorized HTTP/1.1 200 OK ``` El segundo comando pide la contraseña. Si el directorio está vacío, verás `403` o `404` en lugar de `200`, lo que igualmente indica que la autenticación se ha superado. La autenticación básica envía las credenciales codificadas pero sin cifrar, así que úsala solo sobre HTTPS. ## Paso 8: Bloquear el acceso a archivos sensibles Apache ya deniega en Ubuntu el acceso a los archivos que empiezan por `.ht` (como el propio `.htaccess`). Añade reglas para otros archivos que no deben descargarse nunca, como copias de seguridad, configuraciones o el directorio `.git`, y desactiva los listados de directorios. En el `.htaccess` de la raíz: ```apache Options -Indexes Require all denied RewriteRule (^|/)\.git(/|$) - [R=404,L] ``` - `Options -Indexes` hace que un directorio sin `index` devuelva `403` en lugar de listar su contenido. - `FilesMatch` con `Require all denied` devuelve `403` para las extensiones indicadas. - La `RewriteRule` responde `404` a cualquier ruta dentro de `.git`, como si no existiera, sin confirmar su presencia. Colócala justo después de `RewriteEngine On`, antes de las reglas del paso 6, para que se evalúe primero. Compruébalo. La primera prueba solo devuelve `403` si existe un archivo `.env` en la raíz del sitio: ```bash curl -sI https://your_domain/.env | head -n 1 curl -sI https://your_domain/.git/config | head -n 1 ``` ```output HTTP/1.1 403 Forbidden HTTP/1.1 404 Not Found ``` ## Paso 9: Añadir cabeceras de caché y seguridad `mod_expires` indica al navegador cuánto tiempo puede reutilizar cada tipo de archivo sin volver a pedirlo. Aplícalo a los recursos estáticos que llevan versión en el nombre o cambian poco: ```apache ExpiresActive On ExpiresByType image/webp "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/svg+xml "access plus 1 month" ExpiresByType text/css "access plus 1 week" ExpiresByType text/javascript "access plus 1 week" ExpiresByType application/javascript "access plus 1 week" ExpiresByType font/woff2 "access plus 1 year" ``` No asignes una caché larga al HTML, o los visitantes tardarán en ver los cambios del sitio. Añade también algunas cabeceras de seguridad con `mod_headers`: ```apache Header always set X-Content-Type-Options "nosniff" Header always set X-Frame-Options "SAMEORIGIN" Header always set Referrer-Policy "strict-origin-when-cross-origin" ``` Comprueba las cabeceras de un archivo CSS de tu sitio (sustituye la ruta por una real): ```bash curl -sI https://your_domain/css/style.css | grep -iE 'cache-control|expires|x-content-type' ``` ```output Cache-Control: max-age=604800 Expires: Fri, 02 Oct 2026 10:00:00 GMT X-Content-Type-Options: nosniff ``` ## Páginas de error personalizadas Con `ErrorDocument` puedes sustituir las páginas de error genéricas de Apache por las tuyas. La ruta es relativa al `DocumentRoot`: ```apache ErrorDocument 404 /errores/404.html ErrorDocument 403 /errores/403.html ``` Crea los archivos en `/var/www/your_domain/errores/` y comprueba que una URL inexistente devuelve tu página con el código `404`. ## Solución de problemas - **Las reglas no hacen nada**: Apache no lee el archivo. Repite la prueba del paso 3; si no obtienes un 500, revisa `AllowOverride` en el VirtualHost que realmente atiende el dominio. - **`500 Internal Server Error` tras editar el archivo**: hay un error de sintaxis o se usa un módulo no habilitado. `sudo tail /var/log/apache2/error.log` indica la línea y la directiva. - **`Invalid command 'RewriteEngine'` o `'Header'` en el log**: el módulo no está activo. Actívalo con `sudo a2enmod rewrite` o `sudo a2enmod headers` y reinicia Apache. - **`ERR_TOO_MANY_REDIRECTS`**: el sitio está detrás de un proxy o CDN que termina TLS y la regla `%{HTTPS} off` se cumple siempre. Usa la variante con `X-Forwarded-Proto` del paso 4. - **`options not allowed here` en el log**: `AllowOverride` no incluye la categoría de esa directiva (por ejemplo `Options` necesita `AllowOverride Options` o `All`). ## Conclusión Has habilitado `.htaccess` en Apache, has comprobado que el servidor lo lee y lo has usado para forzar HTTPS con un dominio canónico, redirigir páginas, crear URL limpias, proteger un directorio con contraseña, bloquear archivos sensibles y añadir cabeceras de caché y seguridad. Como siguientes pasos puedes: - Mover las reglas estables al VirtualHost y volver a `AllowOverride None` si no necesitas que se cambien sin acceso root, para ganar rendimiento. - Activar la compresión de respuestas con `mod_deflate` o `mod_brotli`. - Añadir la cabecera `Strict-Transport-Security` una vez que todo el sitio funcione solo por HTTPS.