Skip to content
Advertisement

htaccess returns 404 at WordPress in subdirectory (desktop ok, mobile 404)

I have a website made in WordPress, installed in a subdirectory (let’s call it “wp_dir”). I have followed the instructions in https://wordpress.org/support/article/giving-wordpress-its-own-directory/, specifically:

  • change the root htaccess file
  • change the root index.php file
  • change the wp_dir htaccess file

It works well, in desktop, but not in mobile. In desktop, the site is rendered well: when you type “example.com”, it renders the wordpress site well, from the wordpress installed in wp_dir folder, with SSL and everything. All menu links work well.

In mobile, instead, when you type “example.com”, the url changes to “example.com/wp_dir”, with SSL, and menu links are shown, but shows a 404 error. Links work.

I believe the problem is SSL related. I have also tried removing the [L] directives, in order to allow the instructions to continue being executed, but to no avail. Something is not working ok, or in the proper order, but I can’t find what.

The htaccess file is pretty messed up with many different instructions (SSL, non-www redirection, permissions to other subdirectories for management applications, block exploits, etc). The site was previously built in Joomla. Obviously I’ve done something wrong, but I can’t figure out what that is.

How can it work well when you access it in a desktop computer, and not in a mobile phone?

Here is the current htaccess in the root directory (without the mess):

# SSL rewrite
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,NE]

RewriteBase /
RewriteEngine On

# non-www 
RewriteBase /
RewriteCond %{HTTP_HOST} !^example.com$ [NC]
RewriteCond %{HTTPS} OFF
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]

RewriteCond %{HTTP_HOST} !^example.com$ [NC]
RewriteCond %{HTTPS} ON
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/wp_dir/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /wp_dir/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ wp_dir/index.php [L] 
</IfModule>

And here is the htaccess in the WordPress subdirectory (“wp_dir”):

# Force SSL
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI}  [L,R=301,NE] 

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

In case it’s useful to see the full htacess file (with the mess), here it is:

# SSL rewrite
RewriteEngine On
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,NE]

#RewriteEngine On
#RewriteCond %{HTTPS} off
#RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]

RewriteBase /
RewriteEngine On

## Begin - Rewrite rules to block out some common exploits.
# If you experience problems on your site block out the operations listed below
# This attempts to block the most common type of exploit `attempts` to Joomla!
#
# Block out any script trying to base64_encode data within the URL.
RewriteCond %{QUERY_STRING} base64_encode[^(]*([^)]*) [OR]
# Block out any script that includes a <script> tag in URL.
RewriteCond %{QUERY_STRING} (<|%3C)([^s]*s)+cript.*(>|%3E) [NC,OR]
# Block out any script trying to set a PHP GLOBALS variable via URL.
RewriteCond %{QUERY_STRING} GLOBALS(=|[|%[0-9A-Z]{0,2}) [OR]
# Block out any script trying to modify a _REQUEST variable via URL.
RewriteCond %{QUERY_STRING} _REQUEST(=|[|%[0-9A-Z]{0,2})
# Return 403 Forbidden header and show the content of the root homepage
RewriteRule .* index.php [F]
#
## End - Rewrite rules to block out some common exploits.

## Allow access to 'gui' zone
RewriteRule ^(gui)($|/) - [L]
RewriteRule ^(gui/services)($|/) - [L]
RewriteRule ^(gui/services/api.php)($|/) - [L]
RewriteRule ^(gui/services/.*)($|/) - [L]
RewriteRule ^(gui/services/customers)($|/) - [L]
RewriteRule ^(gui/.*)($|/) - [L]
RewriteCond %{REQUEST_URI} ^/(gui|gui/.*)$
RewriteRule ^.*$ - [L]
RewriteCond %{REQUEST_URI} ^/(gui/services|gui/services/.*)$
RewriteRule ^.*$ - [L]
RewriteCond %{REQUEST_URI} ^/(gui/index.php|gui/index.php*/.*)$
RewriteRule ^.*$ - [L]
RewriteCond %{REQUEST_URI} ^/(gui/services/customers|gui/services/customers/.*)$
RewriteRule ^.*$ - [L]
RewriteCond %{REQUEST_URI} ^/(gui/services/customers)$
RewriteRule ^.*$ - [L]
RewriteCond %{REQUEST_URI} ^/(gui/services)$
RewriteRule ^.*$ - [L]
RewriteCond %{REQUEST_URI} ^/(gui/services/.*)$
RewriteRule ^.*$ - [L]
## End access to 'gui' zone

## Allow access to dir_zone2
RewriteCond %{REQUEST_URI} ^/(dir_zone2/|dir_zone2/.*)$
RewriteRule ^.*$ - [L]


# RewriteCond %{REQUEST_URI} !^/(gui|gui/.*)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

## Joomla SEF Section
# If the requested path and file is not /index.php and the request
# has not already been internally rewritten to the index.php script
RewriteCond %{REQUEST_URI} !^/index.php
# and the request is for something within the component folder,
# or for the site root, or for an extensionless URL, or the
# requested URL ends with one of the listed extensions
RewriteCond %{REQUEST_URI} /component/|(/[^.]*|.(php|html?|feed|pdf|vcf|raw))$ [NC]
# and the requested path and file doesn't directly match a physical file
RewriteCond %{REQUEST_FILENAME} !-f
# and the requested path and file doesn't directly match a physical folder
RewriteCond %{REQUEST_FILENAME} !-d
# internally rewrite the request to the index.php script
RewriteRule .* wp_dir/index.php [L]
#
## End - Joomla! core SEF Section.

RewriteCond %{HTTP_REFERER} !^(http|https)://example.com/.*$      [NC]
RewriteCond %{HTTP_REFERER} !^(http|https)://example.com$      [NC]
RewriteCond %{HTTP_REFERER} !^(http|https)://www.example.com/.*$      [NC]
RewriteCond %{HTTP_REFERER} !^(http|https)://www.example.com$      [NC]
RewriteRule .*.(jpg|jpeg|gif|png|bmp)$ - [F,NC]

# non-www
RewriteBase /
#RewriteCond %{REQUEST_URI} !^/(robots.txt|favicon.ico|sitemap.xml)$
RewriteCond %{HTTP_HOST} !^example.com$ [NC]
# 2017-03-06
RewriteCond %{HTTPS} OFF
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]

#RewriteCond %{REQUEST_URI} !^/(robots.txt|favicon.ico|sitemap.xml)$
RewriteCond %{HTTP_HOST} !^example.com$ [NC]
# 2017-03-06
RewriteCond %{HTTPS} ON
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]


# WordPress
#RewriteCond %{REQUEST_URI} ^/(wp_dir/|wp_dir/.*)$
#RewriteRule ^.*$ - [L]

#RewriteCond %{HTTP_HOST} ^(www.)?example.com$
#RewriteRule ^(/)?$ wp_dir[L]


<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/wp_dir/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /wp_dir/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ wp_dir/index.php [L] 
</IfModule>

EDIT: Added headers

These are the headers obtained with two different browsers.

In Firefox, I get the 301, and url keeps at “http ://www.example.com”.

Response headers:

HTTP/1.1 301 Moved Permanently
Server: Sucuri/Cloudproxy
Date: Thu, 05 Mar 2020 17:31:13 GMT
Content-Type: text/html; charset=iso-8859-1
Content-Length: 335
Connection: keep-alive
X-Sucuri-ID: 15020
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-Sucuri-Cache: HIT

Request headers:

Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1

These are the headers in Chrome, where I get a 404 and url “https ://www.example.com/wp_dir/”:

General:

Request URL: https://www.example.com/wp_dir/
Request Method: GET
Status Code: 404 
Remote Address: 192.124.249.120:443
Referrer Policy: no-referrer-when-downgrade

Response headers:

cache-control: no-cache, must-revalidate, max-age=0
content-encoding: gzip
content-length: 14112
content-security-policy: upgrade-insecure-requests;
content-type: text/html; charset=UTF-8
date: Thu, 05 Mar 2020 17:27:18 GMT
expires: Wed, 11 Jan 1984 05:00:00 GMT
link: <https://www.example.com/wp-json/>; rel="https://api.w.org/"
server: nginx
status: 404
vary: Accept-Encoding,User-Agent
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-sucuri-cache: EXPIRED
x-sucuri-id: 15020
x-xss-protection: 1; mode=block

Request headers:

:authority: www.example.com
:method: GET
:path: /wp_dir/
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: es-ES,es;q=0.9,ca;q=0.8,en;q=0.7,fr;q=0.6,ro;q=0.5,gl;q=0.4
cookie: pll_language=es; wp-settings-1=editor%3Dtinymce%26edit_element_vcUIPanelWidth%3D1379%26edit_element_vcUIPanelLeft%3D0px%26edit_element_vcUIPanelTop%3D74px%26libraryContent%3Dbrowse; wp-settings-time-1=1580451182; wordpress_test_cookie=WP+Cookie+check; _ga=GA1.2.2063032164.1566356615; __utma=98619150.2063032164.1566356615.1566523591.1566602595.2; d50c875bad7fd1a5e131e638c3965ba3=es-ES; pll_language=es; wordpress_test_cookie=WP+Cookie+check
sec-fetch-mode: navigate
sec-fetch-site: none
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36

Advertisement

Answer

I think there might be a problem with your rewrite in the subdirectory. First I presume you want to keep the same link. If we look at the tutorial linked there is only need for one .htaccess in the root directory.

Since if a request is made anywhere on the site and if it’s not a direct file or directory the root htaccess file will redirect it to the subfolder.

Now, your second subfolder .htaccess file is actually pointing back to the root directory. If you want to have a .htaccess redirect in the subfolder you should add the rewrite base and the subfolder to the redirect.

# Force SSL
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI}  [L,R=301,NE] 

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /wp_dir/
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /wp_dir/index.php [L]
</IfModule>
# END WordPress
  1. If you look at this Hostinger tutorial it suggests you shouldn’t use the RewriteEngine On condition twice. And this is a nice explanation of this “problem”.

But summery if you use RewriteEngine or RewriteBase multiple times the last entry wins and is used throughout the .htaccess file.

Now I don’t understand did you access https://example.com/wp_dir/ directly or were you redirected there? If it was direct access I think the .htaccess was wrong as I pointed out.

Or it may be the phone cache.

Edit: And also modify the first .htaccess file. I think one https rewrite rule is redundant and another incorrect.

# SSL rewrite
RewriteEngine On
# RewriteCond %{SERVER_PORT} 80
# I think this shouldn't matter but lets use the same method for consistency
RewriteCond %{HTTPS} Off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,NE]

RewriteBase /
# RewriteEngine is already On
# RewriteEngine On

# non-www 
# RewriteBase /
# RewriteBase is already defined
# if we want to redirect to https lets specify that
#RewriteCond %{HTTP_HOST} !^example.com$ [NC]
#RewriteCond %{HTTPS} OFF
# RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]
#RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
# But I think the very first directive should take care of this

# If we're using https why redirect to it?
# Or am I missing something?
#RewriteCond %{HTTP_HOST} !^example.com$ [NC]
#RewriteCond %{HTTPS} ON
#RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/wp_dir/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /wp_dir/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ wp_dir/index.php [L] 
</IfModule>

File as I’d put it

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{HTTPS} Off
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,NE]

  RewriteCond %{HTTP_HOST} ^(www.)?example.com$
  RewriteCond %{REQUEST_URI} !^/wp_dir/
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^(.*)$ /wp_dir/$1
  RewriteCond %{HTTP_HOST} ^(www.)?example.com$
  RewriteRule ^(/)?$ wp_dir/index.php [L] 
</IfModule>

I may be wrong.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement