Remove public from URL

User
# Start: Block all search engine bots from accessing the site – (Do not Edit)

RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (googlebot|bingbot|baiduspider|yandex|duckduckbot) [NC]
RewriteRule .* – [F,L]

Header set X-Robots-Tag "noindex, nofollow"

# New rule to override robots.txt
RewriteEngine On
RewriteRule ^robots.txt$ robots.txt [L]
# End: Block all search engine bots from accessing the site – (Do not Edit)
remove public from url in silstripe cms

Assistant
Got it 👍 You want to **remove `/public` from the site URL** in your SilverStripe CMS.
That means your website should load from `https://example.com/` instead of `https://example.com/public/`.

Here’s the correct way to do it:

### ✅ Steps to Remove `/public` from URL in SilverStripe CMS

1. **Move `index.php` and `.htaccess` up one level**
– Copy the following files from the `/public` folder to your project root:
– `index.php`
– `.htaccess`

2. **Update `index.php` include path**
– Open the `index.php` you just moved.
– Find:

require_once __DIR__ . '/vendor/autoload.php';

– Change it to:

require_once __DIR__ . '/public/vendor/autoload.php';

– And for the line:

require_once __DIR__ . '/vendor/silverstripe/framework/src/includes/constants.php';

– Change it to:

require_once __DIR__ . '/public/vendor/silverstripe/framework/src/includes/constants.php';

3. **Fix `.htaccess` paths**
– In the `.htaccess` you copied, update any reference to `/public/` if present.
– Most of the time you don’t need to change much unless you had custom rules.

4. **Update Apache/Nginx DocumentRoot**
– Instead of pointing your DocumentRoot to `/public`, point it to your project root.
– For Apache (example):

DocumentRoot /var/www/yourproject
     <Directory /var/www/yourproject>
         AllowOverride All
         Require all granted
     </Directory>

5. **Clear caches**
– Run:

vendor/bin/sake dev/build flush=all

– Or append `?flush=1` to your site URL.

👉 This way, SilverStripe will still use `public` internally for assets, but the user-facing URL will no longer include `/public`.

Do you want me to give you the **exact modified `index.php` code** ready to paste after moving it from `/public` to root?

User
using .htaccess
Assistant
Alright 👍 if you don’t want to move files and only want to **hide `/public` using `.htaccess`**, you can set up a rewrite so that requests to `https://example.com/` are internally sent to `/public`.

That means `/public` will stay in your folder structure, but users won’t see it in the URL.

### ✅ `.htaccess` solution (place in project root, not inside `/public`):

# Enable Rewrite
<IfModule mod_rewrite.c>
    RewriteEngine On

    # If request is for an existing file or folder in root, allow it
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    # Send everything else to /public
    RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

### How it works:
– When someone visits `https://example.com/`, the `.htaccess` forwards the request to `/public/index.php`.
– Direct file access (like `/assets/`, `/robots.txt`, `/favicon.ico`) will still work without showing `/public`.
– You keep SilverStripe’s recommended `/public` separation for security.

👉 This is the **safe and recommended way** if you want to hide `/public` but keep SilverStripe’s folder structure intact.

Do you want me to also adjust this so it **merges with your existing `.htaccess` that blocks bots** (the code you pasted earlier)?

User
# Start: Block all search engine bots from accessing the site – (Do not Edit)

RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (googlebot|bingbot|baiduspider|yandex|duckduckbot) [NC]
RewriteRule .* – [F,L]

Header set X-Robots-Tag "noindex, nofollow"

# New rule to override robots.txt
RewriteEngine On
RewriteRule ^robots.txt$ robots.txt [L]
# End: Block all search engine bots from accessing the site – (Do not Edit)
update above

Assistant
Perfect 👍 I’ll merge your **bot-blocking rules** with the **remove `/public` from URL** rewrite.
You only need one `RewriteEngine On` and all rules should be inside the same “ block.

Here’s the cleaned-up version:

# Start: Block all search engine bots from accessing the site - (Do not Edit)

<IfModule mod_rewrite.c>
    RewriteEngine On

    # Block major bots
    RewriteCond %{HTTP_USER_AGENT} (googlebot|bingbot|baiduspider|yandex|duckduckbot) [NC]
    RewriteRule .* - [F,L]

    # Rewrite requests to /public (remove "public" from URL)
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ public/$1 [L]

    # Override robots.txt
    RewriteRule ^robots.txt$ robots.txt [L]
</IfModule>

<IfModule mod_headers.c>
    Header set X-Robots-Tag "noindex, nofollow"
</IfModule>

# End: Block all search engine bots from accessing the site - (Do not Edit)

### 🔎 What changed:
1. Only one `RewriteEngine On`.
2. Added rules to forward everything into `/public` (so `/public` doesn’t appear in URL).
3. Kept your bot-blocking and robots.txt override intact.

👉 Put this **in your project root `.htaccess`** (where `/public` folder lives).

Do you also want me to make sure **`robots.txt` inside `/public`** is still used correctly, even after hiding `/public`?

User
still showing all folder and site home page only work when /public
Assistant
Ah 👍 got it — if you still see folders listed and the homepage only works when you add `/public`, that means Apache isn’t **forcing requests into `/public/index.php`** correctly.

Let me fix this for you.

### ✅ Correct `.htaccess` (root folder)
Put this in your **project root** (same level as `/public`):

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /

    # 1. Block bots
    RewriteCond %{HTTP_USER_AGENT} (googlebot|bingbot|baiduspider|yandex|duckduckbot) [NC]
    RewriteRule .* - [F,L]

    # 2. Redirect everything to /public/
    RewriteCond %{REQUEST_URI} !^/public/
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ public/$1 [L]

    # 3. Override robots.txt (must come after public rule)
    RewriteRule ^robots.txt$ robots.txt [L]
</IfModule>

<IfModule mod_headers.c>
    Header set X-Robots-Tag "noindex, nofollow"
</IfModule>

### 🔎 Why your old one failed
– Apache was still serving the root directory listing because no `DirectoryIndex` or rewrite was catching `/`.
– The `RewriteRule ^(.*)$ public/$1` was being skipped for `/` (homepage).
– That’s why only `/public` worked.

### ✅ Extra step: Disable directory listing
If you don’t want users to see all folders when visiting `/`, add this to the same `.htaccess`:

Options -Indexes
DirectoryIndex index.php index.html

### End result:
– Visiting `https://example.com/` → internally serves `/public/index.php`.
– All subpages (`/about`, `/contact`) → served from `/public/` automatically.
– No more `/public` in the URL.
– No folder listing exposed.

👉 Do you want me to merge `Options -Indexes` + `DirectoryIndex` into your final `.htaccess` so you can just paste and go?

User
still not work
Assistant
Okay 👍 if it **still only works with `/public`**, that means Apache is not actually rewriting to `/public/index.php`. Let’s fix it step by step and give you a guaranteed working `.htaccess`.

### ✅ Final `.htaccess` for root (put in the project root, same level as `/public`)

Options -Indexes
DirectoryIndex public/index.php

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /

    # 1. Block bots
    RewriteCond %{HTTP_USER_AGENT} (googlebot|bingbot|baiduspider|yandex|duckduckbot) [NC]
    RewriteRule .* - [F,L]

    # 2. Force everything into /public
    RewriteCond %{REQUEST_URI} !^/public/
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ public/$1 [L]

    # 3. Override robots.txt (so /robots.txt is used from root)
    RewriteRule ^robots.txt$ robots.txt [L]
</IfModule>

<IfModule mod_headers.c>
    Header set X-Robots-Tag "noindex, nofollow"
</IfModule>

### 🔎 Key Fixes
1. **`DirectoryIndex public/index.php`** → makes homepage (`/`) load `/public/index.php`.
2. **`Options -Indexes`** → disables folder listing.
3. The rewrite now only triggers if the request is not already going into `/public`.

### 🚀 What you should see
– `https://example.com/` → loads `/public/index.php` (SilverStripe homepage).
– `https://example.com/about` → loads `/public/about` internally.
– No more directory listing.
– `/public` never shows in URL.

⚡ Important: After updating `.htaccess`, clear cache & restart Apache:

sudo service apache2 restart

👉 Do you want me to also give you the **Apache VirtualHost config** version (cleaner, no need for `.htaccess` rewrites), in case `.htaccess` still doesn’t take effect?

Leave a Comment

Your email address will not be published. Required fields are marked *