Índice de contenido
- Por qué aparece /public o /index.php en Laravel y por qué afecta al SEO
- Duplicación de URLs y riesgo en producción
- Limitaciones de hosting compartido y servidores mal configurados
- Configuración correcta del virtual host / root
- Errores comunes: loops, NotFound y mod_rewrite deshabilitado
- Mi método alternativo: eliminar public o index.php desde AppServiceProvider (último recurso)
- Cómo detectar carpetas en la URL con Str::contains
- Redirección 301 automática y segura
- Ejemplo completo de implementación
- Consideraciones de seguridad (evitar exponer .env o rutas internas)
- Consejos finales para producción y SEO
- Preguntas frecuentes
Muchas veces cuando estamos desarrollando un proyecto en Laravel y lo pasamos a producción, vemos errores que aparece en la URL, la carpeta public o el archivo index.php:
// Valid URL
https://example.com/blog
// Invalid URL
https://example.com/index.php/blog
https://example.com/public/blogY aunque funcionen, no son nada bonitas, generan contenido duplicado y pueden provocar penalizaciones en SEO. Lo he visto varias veces al subir proyectos a servidores limitados donde no tienes control total sobre Apache o Nginx. La típica situación en la que pruebas todo lo que encuentras en Internet… y nada funciona. Si estás exactamente ahí, respira: hay otros caminos.
En esta guía te explico cómo limpiar completamente las URLs, cuándo usar .htaccess, cuándo no, y cómo aplicar una solución final mediante PHP desde AppServiceProvider cuando ya lo has intentado todo y el servidor no colabora.
Por qué aparece /public o /index.php en Laravel y por qué afecta al SEO
Laravel fue diseñado para que todo el tráfico entre por public/, y hace sentido: esa carpeta contiene el index.php que actúa como front controller y protege el resto del framework. El problema es que, en algunos servidores, en lugar de apuntar al directorio public, la configuración apunta al directorio raíz del proyecto, haciendo que el navegador intente “adivinar” rutas.
Lo cual, si tenemos un blog, esto nos puede traer penalizaciones con el SEO; en esta entrada vamos a ver como reparar este problema, no desde el htacces que muchas veces no funciona y que hay muchos ejemplos de como hacerlo en Internet, si no, mediante código PHP, por lo tanto, si estas desesperado, esta es la última medida que puedes implementar.
Duplicación de URLs y riesgo en producción
En mi caso, la primera vez que me encontré esto, Google comenzó a indexar rutas extrañas con /public/ y con /index.php/. Y claro, eso no solo parece amateur, también produce contenido duplicado. Google detecta dos URLs distintas para el mismo contenido, y el posicionamiento se resiente.
A nivel SEO, esto afecta en:
- Canónicas incorrectas
- Competencia interna
- Redirecciones inconsistentes
- Disminución del crawl budget
Limitaciones de hosting compartido y servidores mal configurados
¿El problema? Si mod_rewrite está desactivado o el hosting no permite overrides, esto no sirve de absolutamente nada.
Configuración correcta del virtual host / root
La solución oficial de Laravel siempre es:
DocumentRoot /proyecto/publicPero esto requiere acceso a Apache/Nginx. Si estás en un entorno donde no tienes permisos, olvídalo.
Errores comunes: loops, NotFound y mod_rewrite deshabilitado
Varios de los competidores tenían usuarios con errores como:
- AH00124: Request exceeded the limit of 100 internal redirects
- “Not found” al eliminar /public/index.php
- “Forbidden” al acceder al proyecto sin /public/
- El .htaccess simplemente se ignora
Me pasó igual: intentas redirigir y terminas entrando en un bucle infinito. Por eso, cuando .htaccess falla, ya no pierdo más tiempo y aplico la solución que te muestro ahora.
Mi método alternativo: eliminar public o index.php desde AppServiceProvider (último recurso)
Cuando estás desesperado porque el servidor no respeta el .htaccess, este método te salva la vida. A mí me ha funcionado en hosting compartido, VPS antiguos y servidores que no permiten modificar configuraciones.
Consiste en interceptar la URL desde Laravel y redirigirla automáticamente con un 301.
Cómo detectar carpetas en la URL con Str::contains
Laravel nos permite analizar la URL entrante desde PHP usando request()->getRequestUri().
Desde ahí puedo comprobar si la URL contiene /public/ o /index.php/.
Redirección 301 automática y segura
Yo uso:
if (Str::contains(request()->getRequestUri(), '/public/')) {
$url = str_replace('public/', '', request()->getRequestUri());
header("Location: $url", true, 301);
exit;
}Y lo mismo para index.php.
Esto fuerza a cualquier cliente o crawler a ver siempre la versión limpia. La ventaja SEO es inmediata: Google deja de rastrear las rutas incorrectas.
Ejemplo completo de implementación
Si además estás en un hosting limitado o un VPS sin permisos para modificar virtual hosts, modificar sites-available, o sin control sobre los módulos de Apache, lo habitual es que el .htaccess no funcione.
Esto me pasó varias veces: te rompes la cabeza editando .htaccess, y al final el servidor lo ignora. Ahí es donde empecé a usar un método por PHP como último recurso.
Para remover la carpeta public y/o index.php de la URL, lo que debemos de hacer es ir al proveedor de nuestra aplicación:
app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->removePublicPHPFromURL();
}
protected function removePublicPHPFromURL()
{
if (Str::contains(request()->getRequestUri(), '/public/')) {
$url = str_replace('public/', '', request()->getRequestUri());
if (strlen($url) > 0) {
header("Location: $url", true, 301);
exit;
}
}
}
}O si quieres para remover el index.php, queda como:
app/Providers/AppServiceProvider.php
protected function removeIndexPHPFromURL()
{
if (Str::contains(request()->getRequestUri(), '/index.php/')) {
$url = str_replace('index.php/', '', request()->getRequestUri());
if (strlen($url) > 0) {
header("Location: $url", true, 301);
exit;
}
}
}En ambos casos, como puedes ver, simplemente verificamos mediante el request, si existe la carpeta de index.php o la carpeta public y la removemos, luego, hacemos una redirección de tipo 301 que significa que indica que es una redirección permanente a la misma URL quitando la carpeta public e index.php; código completo:
app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->removePublicPHPFromURL();
$this->removeIndexPHPFromURL();
}
protected function removePublicPHPFromURL()
{
if (Str::contains(request()->getRequestUri(), '/public/')) {
$url = str_replace('public/', '', request()->getRequestUri());
header("Location: $url", true, 301);
exit;
}
}
protected function removeIndexPHPFromURL()
{
if (Str::contains(request()->getRequestUri(), '/index.php/')) {
$url = str_replace('index.php/', '', request()->getRequestUri());
header("Location: $url", true, 301);
exit;
}
}
}Consideraciones de seguridad (evitar exponer .env o rutas internas)
Una de las advertencias más importantes en los foros —y que también he sufrido— es que mover el index.php al root o servir Laravel desde / puede dejar expuestas rutas como:
https://midominio.com/.envTu aplicación queda abierta como un libro.
La ventaja de mi método es que no requieres mover nada. Todo sigue protegido como Laravel manda: desde la carpeta public.
Consejos finales para producción y SEO
- Haz redirecciones 301, nunca 302
- Mantén un sitemap actualizado después de limpiar las URLs
- Revisa Search Console para detectar duplicaciones antiguas
- Mantén public/ como punto de entrada real, incluso si las URLs limpias lo ocultan
- Testea varias rutas: /blog, /blog/, /css/app.css
- Si más adelante tienes control del servidor, configura correctamente el DocumentRoot para prescindir de este “parche”
Preguntas frecuentes
- ¿Es seguro eliminar /public o /index.php desde PHP?
- Sí, porque no mueves archivos sensibles. Solo haces redirecciones.
- ¿Por qué mi .htaccess no funciona?
- Generalmente porque AllowOverride está deshabilitado o mod_rewrite está inactivo.
- ¿Se puede usar este método con cualquier versión de Laravel?
- Funciona desde Laravel 5 hasta Laravel 13.
- ¿Afecta esto al rendimiento?
- La condición se evalúa en microsegundos y solo cuando la URL contiene /public/ o /index.php/.
- ¿Esto corrige el SEO automáticamente?
- Ayuda muchísimo, pero igual debes limpiar URLs antiguas en Search Console.