Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wordpress subdirectory multisite setup can't get it to work #916

Closed
yosefy opened this issue Aug 2, 2023 · 75 comments
Closed

wordpress subdirectory multisite setup can't get it to work #916

yosefy opened this issue Aug 2, 2023 · 75 comments
Assignees
Labels
z-bug 🐞 z-documentation-update-needed This type of issues likely have a link to an issue in the Unit Docs repo z-question z-roadmap
Milestone

Comments

@yosefy
Copy link

yosefy commented Aug 2, 2023

i just can't managed to get it working
examples i have are here: https://www.nginx.com/resources/wiki/start/topics/recipes/wordpress/#rewrite-rules-for-multisite-using-subdirectories

but it just won't work for unit in no way and that is sad because we can't move half of our sites

something with rewrite rules on paths like /aaa/ , /bbb/ (permalinks type)

single site wordpress works great

may be you can help with working config?
i can do the testing

i think many people still use wordpress

thanks

@tippexs
Copy link
Contributor

tippexs commented Aug 11, 2023

Hi @yosefy thanks for reporting this to us. We are just released a very basic implementation of URI-Rewrite to Units Router with the last release.
See the documentation.
https://unit.nginx.org/configuration/#uri-rewrite

Please share the Unit Configuration you are using so far.

So basically what you are trying to do is running multiple WPs sites on a single Domain (foo.com) seperated by different directories like /a/ and /b/. The Hostname configured in WP will be https://foo.com/a/ or https://foo.com/b/? Am I getting this correct? I haven't tried that but will work on it over the weekend and let you know.

@yosefy
Copy link
Author

yosefy commented Aug 11, 2023 via email

@tippexs tippexs added z-documentation-update-needed This type of issues likely have a link to an issue in the Unit Docs repo z-question labels Aug 12, 2023
@yosefy
Copy link
Author

yosefy commented Aug 14, 2023

waiting for you answer. it is kind of deal breaker as for now for all the multisite i have to install nginx. which removes the whole idea of one tool doing it all. thanks

btw problem not only with multisite, but also with site that has siteurl as mainsite/blog

and wordpress is installed at /blog

now rewrites for nginx work as expected but for unit i couldn't find working config

i guess it is part of same problem

thanks

@yosefy
Copy link
Author

yosefy commented Aug 15, 2023

more info:
request to /he/wp-admin/

so you can see that apache only overwrites SCRIPT_NAME and SCRIPT_FILENAME
while uri stays the same

but when we do rewrite in unit it rewrites URI and there is no option to only change script name (we can't use variables in this field).

because in wordpress there is no real file in /he/wp-admin/ but it needs to keep uri as it redirects by it to next stage
for example to /he/wp-login.php. otherwise we are redirected to /wp-login.php without site dir prefix

when proxy with apache i see next headers:

curl 'http://sitename.com/he/wp-admin/index.php'

$_SERVER["USER"] == apache
$_SERVER["HOME"] == /usr/share/httpd
$_SERVER["SCRIPT_NAME"] == /wp-admin/index.php
$_SERVER["REQUEST_URI"] == /he/wp-admin/
$_SERVER["QUERY_STRING"] ==
$_SERVER["REQUEST_METHOD"] == GET
$_SERVER["SERVER_PROTOCOL"] == HTTP/1.0
$_SERVER["GATEWAY_INTERFACE"] == CGI/1.1
$_SERVER["REDIRECT_URL"] == /he/wp-admin/
$_SERVER["REMOTE_PORT"] == 37370
$_SERVER["SCRIPT_FILENAME"] == /sites/sitename.com/public/wp-admin/index.php
$_SERVER["SERVER_ADMIN"] == root@localhost
$_SERVER["CONTEXT_DOCUMENT_ROOT"] == /sites/sitename.com/public
$_SERVER["CONTEXT_PREFIX"] ==
$_SERVER["REQUEST_SCHEME"] == http
$_SERVER["DOCUMENT_ROOT"] == /sites/sitename.com/public
$_SERVER["REMOTE_ADDR"] == X.X.X.X
$_SERVER["SERVER_PORT"] == 80
$_SERVER["SERVER_ADDR"] == X.X.X.X
$_SERVER["SERVER_NAME"] == sitename.com
$_SERVER["SERVER_SOFTWARE"] == Apache/2.4.6 (CentOS)
$_SERVER["SERVER_SIGNATURE"] ==
$_SERVER["PATH"] == /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
$_SERVER["HTTP_COOKIE"] == wp-settings-time-77=1689343065;
$_SERVER["HTTP_ACCEPT_LANGUAGE"] == en-US,en;q=0.9,he;q=0.8,ru;q=0.7,fr;q=0.6
$_SERVER["HTTP_ACCEPT_ENCODING"] == gzip, deflate
$_SERVER["HTTP_ACCEPT"] == text/html,application/x
$_SERVER["HTTP_USER_AGENT"] == Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
$_SERVER["HTTP_UPGRADE_INSECURE_REQUESTS"] == 1
$_SERVER["HTTP_CONNECTION"] == close
$_SERVER["HTTP_X_FORWARDED_PROTO"] == http
$_SERVER["HTTP_X_FORWARDED_HOST"] == sitename.com
$_SERVER["HTTP_HOST"] == sitename.com
$_SERVER["proxy-nokeepalive"] == 1
$_SERVER["HTTP_AUTHORIZATION"] ==
$_SERVER["SCRIPT_URI"] == http://sitename.com/he/wp-admin/
$_SERVER["SCRIPT_URL"] == /he/wp-admin/
$_SERVER["UNIQUE_ID"] == XXX
$_SERVER["REDIRECT_STATUS"] == 200
$_SERVER["REDIRECT_HTTP_AUTHORIZATION"] ==
$_SERVER["REDIRECT_SCRIPT_URI"] == http://sitename.com/he/wp-admin/
$_SERVER["REDIRECT_SCRIPT_URL"] == /he/wp-admin/
$_SERVER["REDIRECT_UNIQUE_ID"] == XXX
$_SERVER["FCGI_ROLE"] == RESPONDER
$_SERVER["PHP_SELF"] == /wp-admin/index.php

while in unit

curl 'http://site.com/he/wp-admin/index.php'

$_SERVER["SERVER_SOFTWARE"] == Unit/1.30.0
$_SERVER["SERVER_PROTOCOL"] == HTTP/1.0
$_SERVER["PHP_SELF"] == /wp-admin/index.php
$_SERVER["SCRIPT_NAME"] == /wp-admin/index.php
$_SERVER["SCRIPT_FILENAME"] == /sites/ideology.kbb1.com/wp-admin/index.php
$_SERVER["DOCUMENT_ROOT"] == /sites/ideology.kbb1.com
$_SERVER["REQUEST_METHOD"] == GET
$_SERVER["REQUEST_URI"] == /wp-admin/index.php
$_SERVER["QUERY_STRING"] ==
$_SERVER["REMOTE_ADDR"] == X.X.X.X
$_SERVER["SERVER_ADDR"] == X.X.X.X
$_SERVER["SERVER_NAME"] == site.com
$_SERVER["SERVER_PORT"] == 80
$_SERVER["HTTP_HOST"] == site.com
$_SERVER["HTTP_X_FORWARDED_HOST"] == site.com
$_SERVER["HTTP_X_FORWARDED_FOR"] == XXX
$_SERVER["HTTP_X_FORWARDED_PROTO"] == http
$_SERVER["HTTP_CONNECTION"] == close
$_SERVER["HTTP_CACHE_CONTROL"] == max-age=0
$_SERVER["HTTP_UPGRADE_INSECURE_REQUESTS"] == 1
$_SERVER["HTTP_USER_AGENT"] == Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
$_SERVER["HTTP_ACCEPT"] == text/html,application/xhtml+xml,appl
$_SERVER["HTTP_ACCEPT_ENCODING"] == gzip, deflate
$_SERVER["HTTP_ACCEPT_LANGUAGE"] == en-US,en;q=0.9,he;q=0.8,ru;q=0.7,fr;q=0.6
$_SERVER["HTTP_COOKIE"] == __utmc=103998
$_SERVER["REQUEST_TIME_FLOAT"] == 1692117203.0799
$_SERVER["REQUEST_TIME"] == 1692117203
{
	"access_log": {
		"path": "/var/log/unit/access.log",
		"format": "{\"source\":\"nginx\",\"host\":\"$host\", \"remote_addr\":\"$remote_addr\", \"time_local\":\"$time_local\", \"request\":\"$request_line\", \"status\":\"$status\", \"bytes_sent\":\"$body_bytes_sent\", \"referer\": \"$header_referer\", \"user_agent\": \"$header_user_agent\"}"
	},

	"settings": {
		"http": {
			"log_route": true
		}
	},

	"listeners": {
		"*:80": {
			"pass": "routes",
			"forwarded": {
				"client_ip": "X-Forwarded-For",
				"recursive": true,
				"source": [
					"10.0.0.0/8",
					"127.0.0.1"
				]
			}
		}
	},

	"routes": [
		{
			"match": {
				"uri": [
					"/wp-admin"
				]
			},

			"action": {
				"rewrite": "http://$host$uri/",
				"pass": "applications/$host/direct"
			}
		},
		{
			"match": {
				"uri": "~^(\\/[^\\/]+)?(\\/.*\\.php)$"
			},

			"action": {
				"rewrite": "`${uri.replace(/^(\\/[^\\/]+)?(\\/.*\\.php)/, '$2')}`",
				"pass": "applications/$host/direct"
			}
		},
		{
			"match": {
				"uri": "~^(/[^/]+)?(/wp-.*)$"
			},

			"action": {
				"rewrite": "`${uri.replace(/^(\\/[^\\/]+)?(\\/wp-.*)/, '$2')}`",
				"share": "/sites/$host$uri",
				"fallback": {
					"pass": "applications/$host/direct"
				}
			}
		},
		{
			"action": {
				"share": "/sites/$host$uri",
				"fallback": {
					"pass": "applications/$host/index"
				}
			}
		}
	],

	"applications": {
		"sitename.com": {
			"stderr": "/tmp/unit_app.log",
			"type": "php 7.4",
			"targets": {
				"direct": {
					"root": "/sites/sitename.com/"
				},
				"index": {
					"root": "/sites/sitename.com/"
				}
			}
		}
	}
}

@hongzhidao hongzhidao self-assigned this Aug 23, 2023
@hongzhidao
Copy link
Contributor

Hi, @yosefy
Sorry for the late reply, but could you share what you expect based on the above configuration?

  1. What's the request URL?
  2. What's the expected value for the specific option compared to the current value? For example:
$_SERVER["SCRIPT_FILENAME"]:
current: ?
expected: ?

And btw, nginx works well, right? What's the nginx's configuration?
Thanks.

@yosefy
Copy link
Author

yosefy commented Aug 23, 2023

@hongzhidao

for nginx is like this https://www.nginx.com/resources/wiki/start/topics/recipes/wordpress/

current is is whatever you put in application config hardcoded

what we need is like this:

in fastcgi_params they use vars
so in default nginx install you get fastcgi_params:

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REQUEST_SCHEME     $scheme;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

and in nginx config

        location ~ \.php$ {
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
                include fastcgi_params;
                fastcgi_intercept_errors on;
                fastcgi_pass php;
                #The following parameter can be also included in fastcgi_params file
                fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        }

@yosefy
Copy link
Author

yosefy commented Aug 23, 2023

please pay attention to nginx rewrite rules for multisite
https://www.nginx.com/resources/wiki/start/topics/recipes/wordpress/#rewrite-rules-for-multisite-using-subdirectories

thanks

BTW for now we moving all back to php-fpm because we have lots of multisites and we will have to wait for this to be implemented

@hongzhidao
Copy link
Contributor

hongzhidao commented Aug 23, 2023

I still can't understand the question totally.
Which params in PHP are different between Unit and nginx after rewritten?
It would be great if you can show the current value that might be wrong and the expected value that is correct for you.

@yosefy
Copy link
Author

yosefy commented Aug 23, 2023

i have multisite with subdirectory sites
lets say first wp-admin is in /test1/wp-admin/ and second at /test2/wp-admin/
and may be there are more and i don't know what prefix they will be

so as you see in apache in my example
$_SERVER["REQUEST_URI"] == /he/wp-admin/
$_SERVER["REDIRECT_URL"] == /he/wp-admin/
but
$_SERVER["SCRIPT_NAME"] == /wp-admin/index.php
$_SERVER["SCRIPT_FILENAME"] == /sites/sitename.com/public/wp-admin/index.php

so this: RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
doesn't change request_uri really but changes the SCRIPT_NAME

while in unit rewrite rewrites the uri

i have spent lots of hours trying to config it to work

if you can we can have short session so i will show you the problem

thanks

apache with multisite site .htaccess is :

# BEGIN WordPress Multisite
# Using subfolder network type: https://wordpress.org/documentation/article/htaccess/#multisite

RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]

# add a trailing slash to /wp-admin
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]

# END WordPress Multisite

while apache with single site config is :

# BEGIN WordPress

RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

in http conf there is only

    <FilesMatch \.php$>
         SetHandler "proxy:fcgi://127.0.0.1:9026"
    </FilesMatch>

@hongzhidao
Copy link
Contributor

Here's my example to minimize the question.

conf.json

{
    "listeners": {
        "*:8080": {
            "pass": "routes"
        }
    },
    "routes": [
        {
            "action": {
                "rewrite": "/wp-admin/",
                "pass": "applications/app"
            }
        }
    ],
    "applications": {
        "app": {
            "type": "php",
            "root": "/tmp/scripts/"
        }
    }
}

/tmp/scripts/wp-admin/index.php

<?php
print($_SERVER['SCRIPT_FILENAME']);

test

> curl http://127.1:8080/he/wp-admin

/tmp/scripts/wp-admin/index.php

Is it the same as you expected? If it's not, what's your expected value?
Sorry I can't find the problem from nginx and apache configuration, It's better to discuss it based on Unit configuration.

@yosefy
Copy link
Author

yosefy commented Aug 24, 2023 via email

@hongzhidao
Copy link
Contributor

Sure.

Array
(
    [SERVER_SOFTWARE] => Unit/1.31.0
    [SERVER_PROTOCOL] => HTTP/1.1
    [PHP_SELF] => /wp-admin/index.php
    [SCRIPT_NAME] => /wp-admin/index.php
    [SCRIPT_FILENAME] => /tmp/scripts/wp-admin/index.php
    [DOCUMENT_ROOT] => /tmp/scripts
    [REQUEST_METHOD] => GET
    [REQUEST_URI] => /wp-admin/
    [QUERY_STRING] =>
    [REMOTE_ADDR] => 127.0.0.1
    [SERVER_ADDR] => 127.0.0.1
    [SERVER_NAME] => 127.1
    [SERVER_PORT] => 80
    [HTTP_HOST] => 127.1:8080
    [HTTP_USER_AGENT] => curl/7.61.1
    [HTTP_ACCEPT] => */*
    [REQUEST_TIME_FLOAT] => 1692841843.4071
    [REQUEST_TIME] => 1692841843
)

@yosefy
Copy link
Author

yosefy commented Aug 24, 2023 via email

@hongzhidao
Copy link
Contributor

Do you mean [REQUEST_URI] should be /he/wp-admin/ rather than /wp-admin/?

@yosefy
Copy link
Author

yosefy commented Aug 24, 2023 via email

@hongzhidao
Copy link
Contributor

Thanks for confirming it.
Does nginx work well? I didn't install Apache, but I can try it with nginx.

@yosefy
Copy link
Author

yosefy commented Aug 24, 2023 via email

@hongzhidao
Copy link
Contributor

hongzhidao commented Aug 24, 2023

Hi @yosefy,
Thanks for reporting this, good use case.

The [REQUEST_URI] is from the internal r->target, we can regard it as $request_uri.
In NGINX, $request_uri is constant, but in Unit, it's changeable.

All route step actions support the rewrite option that updates the URI of the incoming request before the action is applied. It does not affect the query but changes the uri and $request_uri variables.

It's based on our internal discussion when we implemented it.

We'll discuss it again internally to check which way is more reasonable.
Could you try this patch to check if it can make Unit work well with your case? It makes $request_uri constant.
That would be a good reference for us. Thanks.

unused and deleted.
use the gist patch below instead.

@yosefy
Copy link
Author

yosefy commented Aug 24, 2023 via email

@hongzhidao
Copy link
Contributor

Btw, our team is busy releasing the next 1.31 version, it will be on AUG 31.
We are not sure if we'll have a clear decision soon. But we'll put in on the 1.32.
Let's track it with the development patch way here.

@yosefy
Copy link
Author

yosefy commented Aug 28, 2023

amm took me whole day to compile
you need to mention that main branch on 1.31 and it is not working with modules from 1.30 :)
so it is working for me for multisite with a patch, i can share config if you need

thanks

@tippexs
Copy link
Contributor

tippexs commented Aug 28, 2023

@yosefy sorry to hear that you had such a bad experience! We are aware of this and we will work on better documentation and tooling for that!

@yosefy
Copy link
Author

yosefy commented Aug 30, 2023

amm after rechecking, patch is not working , still it rewrites the url
we need flexibility with index and script

@hongzhidao
Copy link
Contributor

still it rewrites the url

Both $uri and $request_uri are changeable with the official version.
The patch will make $request_uri const, but it's for testing your WP.

And I'm wondering if making $request_uri constant is the only way to meet your requirement.

@yosefy
Copy link
Author

yosefy commented Aug 31, 2023 via email

@hongzhidao
Copy link
Contributor

may be could be gould idea to make it optional because i guess there
are time when someone needs the opposite

Yes, and you could try the example on the unit document.
https://unit.nginx.org/howto/wordpress/

@yosefy
Copy link
Author

yosefy commented Aug 31, 2023 via email

@yosefy
Copy link
Author

yosefy commented Dec 23, 2023

i don't know why it happened with plugins.php

in new config
route 3 (with regex) catches also static files like
http://site/subsite/wp-includes/js/jquery/jquery.min.js?ver=3.6.4

@yosefy
Copy link
Author

yosefy commented Dec 23, 2023

added like this

        {
            "match": {
                "uri": [
                    "~([_0-9a-zA-Z-]+\\/)(wp-(admin|includes|content)/\\.*\\.php)",
                    "~([_0-9a-zA-Z-]+\\/)(wp-(admin|includes|content)/$)"
                ]
            },
            "action": {
                "rewrite": "`${uri.replace(/([_0-9a-zA-Z-]+\\/)(wp-(admin|includes|content)\\/\\.*)/, '$2')}`",
                "pass": "applications/$host/direct",
            }
        },
        {
            "match": {
                "uri": [
                    "~([_0-9a-zA-Z-]+\\/)(wp-(admin|includes|content)/\\.*)"
                ]
            },
            "action": {
                "rewrite": "`${uri.replace(/([_0-9a-zA-Z-]+\\/)(wp-(admin|includes|content)\\/\\.*)/, '$2')}`",
                "share": "/sites/$host$uri",
                "fallback": {
                    "return": 404
                }
            }
        }
'''

first catches php AND strict '/' in the end
and second (was already there) catches the rest (static)
@javorszky what do you say?
may be there is more elegant way for this?

@yosefy
Copy link
Author

yosefy commented Dec 23, 2023

the question now.
so we catch

  1. single site
  2. subdir multisite

need to test:

  1. subdomain multisite (i guess will be ok)
  2. subdir single site (not multi but looks like multi ) meaning http://not_multi/sub_dir (happens a lot)
    is it possible to host subdir multisite and subdir not_multisite on same unit?

@yosefy
Copy link
Author

yosefy commented Dec 23, 2023

ah... and the media...
https://site/subsuite/files/2013/06/my-picture.jpg

@javorszky
Copy link
Contributor

javorszky commented Jan 3, 2024

Hi @yosefy, and Happy New Year!

I took a look at some of the additional comments you left me here and discovered an additional misconfiguration issue, so thank you for these.

Here's the revised configuration which now correctly works in all instances that I could find for a subdirectory multisite WordPress installation. I tested the following:

  • see main site publicly, not logged in
  • see subsite publicly, not logged in
  • see a post on the main site, making sure that post is only on the main site
  • see a post on the subsite, making sure that post is supposed to be on the subsite
  • log in and access the main site's wp admin
  • access the subsite's wp admin
  • access the network admin and all of its admin pages
  • create a new post for the main site with an image in it that I uploaded
  • create a new post for the subsite with an image in it that I uploaded
Updated config.json
{
    "settings": {
        "http": {
            "log_route": true
        }
    },
    "listeners": {
        "*:80": {
            "pass": "routes"
        }
    },
    "routes": [
        {
            "match": {
                "uri": [
                    "*.ht*"
                ]
            },
            "action": {
                "return": 404
            }
        },
        {
            "match": {
                "uri": [
                    "index.php"
                ]
            },
            "action": {
                "pass": "applications/wordpress/index"
            }
        },
        {
            "match": {
                "uri": [
                    "*/wp-admin"
                ]
            },
            "action": {
                "rewrite": "$uri/",
                "pass": "routes"
            }
        },
        {
            "match": {
                "uri": [
                    "~([_0-9a-zA-Z-]+\\/)(wp-(admin|includes|content)/\\.*)"
                ]
            },
            "action": {
                "rewrite": "`${uri.replace(/([_0-9a-zA-Z-]+\\/)(wp-(admin|includes|content)\\/\\.*)/, '$2')}`",
                "pass": "routes"
            }
        },
        
        {
            "match": {
                "uri": [
                    "*.*",
                    "!*.php"
                ]
            },
            "action": {
                "share": "/wpms$uri",
                "fallback": {
                    "return": 404
                }
            }
        },
        {
            "match": {
                "uri": [
                    "*.php",
                    "*.php/*",
                    "*/wp-admin/",
                    "*/wp-admin/*/"
                ]
            },
            "action": {
                "pass": "applications/wordpress/direct"
            }
        },
        {
            "action": {
                "share": "/wpms$uri",
                "fallback": {
                    "pass": "applications/wordpress/index"
                }
            }
        }
    ],
    "applications": {
        "wordpress": {
            "type": "php",
            "targets": {
                "direct": {
                    "root": "/wpms/"
                },
                "index": {
                    "root": "/wpms/",
                    "script": "index.php"
                }
            }
        }
    }
}

A while ago you asked why I passed the request back to the routes after rewriting the request URI (stripping the subsite portion of the path) instead of directly handling it. I went back to see what actually happens in Apache. Apache has a base configuration which has things like "deny any .ht* files" and "for any file that has a .php extension, pass it to the php-cgi interpreter". Unit does not have that base configuration, so the order of operations need to happen in a slightly different way.

In Unit's case, first let's rewrite the URI, and then figure out whether it's a php file, a direct call to an index.php file, an actual file that's not a php file (this would be your images / js / css files), or a directory, and depending on that we can pass it to the application directly, through the index, or try to serve the file as-is without involving php.

is it possible to host subdir multisite and subdir not_multisite on same unit?

Yes, with the caveat that they will need two different sets of route configurations. Technically the subdir not multisite is a single site with some wp-config globals set to specific values, so they will need to work differently than a subdir multisite.

That said I'm confident that the solution to the original issue with the patch that @hongzhidao provided works for correctly setting the request uri global variable.

If you're happy with the solution, we can work on getting the code merged and a new version of unit published as soon as it's feasible, and once that's in, we'll close this issue. We can continue discussion about configuring Unit for WordPress in a GitHub discussions page.

@yosefy
Copy link
Author

yosefy commented Jan 3, 2024

@javorszky first of all thatnks
i also have few things to add to this config
also, say, can we may we have short meeting?
may be you have some monthly meeting where i can join to share my use case and questions?
or we can just have half an hour zoom or whatever meeting

what do you say?

thanks

@yosefy
Copy link
Author

yosefy commented Jan 3, 2024

Hi @yosefy, and Happy New Year!

I took a look at some of the additional comments you left me here and discovered an additional misconfiguration issue, so thank you for these.

Here's the revised configuration which now correctly works in all instances that I could find for a subdirectory multisite WordPress installation. I tested the following:

  • see main site publicly, not logged in
  • see subsite publicly, not logged in
  • see a post on the main site, making sure that post is only on the main site
  • see a post on the subsite, making sure that post is supposed to be on the subsite
  • log in and access the main site's wp admin
  • access the subsite's wp admin
  • access the network admin and all of its admin pages
  • create a new post for the main site with an image in it that I uploaded
  • create a new post for the subsite with an image in it that I uploaded

Updated config.json
A while ago you asked why I passed the request back to the routes after rewriting the request URI (stripping the subsite portion of the path) instead of directly handling it. I went back to see what actually happens in Apache. Apache has a base configuration which has things like "deny any .ht* files" and "for any file that has a .php extension, pass it to the php-cgi interpreter". Unit does not have that base configuration, so the order of operations need to happen in a slightly different way.

In Unit's case, first let's rewrite the URI, and then figure out whether it's a php file, a direct call to an index.php file, an actual file that's not a php file (this would be your images / js / css files), or a directory, and depending on that we can pass it to the application directly, through the index, or try to serve the file as-is without involving php.

is it possible to host subdir multisite and subdir not_multisite on same unit?

Yes, with the caveat that they will need two different sets of route configurations. Technically the subdir not multisite is a single site with some wp-config globals set to specific values, so they will need to work differently than a subdir multisite.

That said I'm confident that the solution to the original issue with the patch that @hongzhidao provided works for correctly setting the request uri global variable.

If you're happy with the solution, we can work on getting the code merged and a new version of unit published as soon as it's feasible, and once that's in, we'll close this issue. We can continue discussion about configuring Unit for WordPress in a GitHub discussions page.

if i am coming to site/sub_something

to route it i need to match $host and $uri

but in unit we can't do && . meanding $host=x && uri=Y
so how can i route nicely host1/a1 , host1/b1, host2/a1, host2/b1

it is becoming route insite route....
if we could somehow choose between OR and AND in matching rules...

what do you say?

@hongzhidao
Copy link
Contributor

hongzhidao commented Jan 3, 2024

Hi,

to route it i need to match $host and $uri
but in unit we can't do && . meanding $host=x && uri=Y
so how can i route nicely host1/a1 , host1/b1, host2/a1, host2/b1

Do you mean something like this?

[
    {
        "match": {
           "host": "host1",
           "uri": "/a1"
        },
        "action": {},
    },
    {
          "match": {
             "host": "host2",
             "uri": "/a2 
          },
          "action": {}
    },
    ...
]

In the configuration, the logic inside the match block means host == '...' && uri == '...'.

if we could somehow choose between OR and AND in matching rules...

This is in our plan, we plan to support JS script conditions, for example:

{
  "match": {
    "if": "`${host == '...' || uri == '...'}`"
  }
}

@yosefy
Copy link
Author

yosefy commented Jan 3, 2024 via email

@hongzhidao
Copy link
Contributor

in this case it will catch first one machine host without checking uri

Sorry that I can't understand what you mean, for the match object.

"match": {
  "host": "host1",
  "uri": "/a2"
}

As I understand, only the request with host == host1 && uri == /a2 matches it.

@yosefy
Copy link
Author

yosefy commented Jan 3, 2024 via email

@hongzhidao
Copy link
Contributor

but as docs say if host1 matches , /a2 doesn't matter. because the logic is

Could you show the related doc link or content?

I found a similar rule on the document website.

The following example combines all matching types. Here, host, method, uri, arg1 and arg2, either cookie1 or cookie2, and either header1 or header2 and header3 must be matched for the action to be taken (host & method & uri & arg1 & arg2 & (cookie1 | cookie2) & (header1 | (header2 & header3))):

{
    "match": {
        "host": "pattern",
        "method": "!pattern",
        "uri": [
            "pattern",
            "!pattern"
        ],

        "arguments": {
            "arg1": "pattern",
            "arg2": "!pattern"
        },

        "cookies": [
            {
                "cookie1": "pattern",
            },
            {
                "cookie2": "pattern",
            }
        ],

        "headers": [
            {
                "header1": "pattern",
            },
            {
                "header2": "pattern",
                "header3": "pattern"
            }
        ]
    },

    "action": {
        "pass": "..."
    }
}

@yosefy
Copy link
Author

yosefy commented Feb 28, 2024

@tippexs what is z-roadmap
meaning when it will hit release?
@javorszky thanks for great work

thanks

@hongzhidao
Copy link
Contributor

Hi all,
I created a PR related to this issue, welcome to discuss and test it, thanks!
#1162

hongzhidao added a commit to hongzhidao/unit that referenced this issue Apr 15, 2024
Previously, the REQUEST_URI within Unit could be modified,
for example, during uri rewritting. We plan to make $request_uri
immutable and pass constant REQUEST_URI to applications.
Based on the new requirement, we remove `r->target` rewritting
in the rewrite module.

Closes: nginx#916
@javorszky
Copy link
Contributor

I put together a test harness and test suite to make sure that all endpoints and rewrites behave expectedly, including the rest api. That all passes, so from a functionality point of view this works as WordPress expects to work in subsite mode. There will be a writeup on the test, but I wanted to give a 👍🏻 for this issue to get it moving along 🙂

hongzhidao added a commit to hongzhidao/unit that referenced this issue Apr 16, 2024
Previously, the REQUEST_URI within Unit could be modified,
for example, during uri rewritting. We plan to make $request_uri
immutable and pass constant REQUEST_URI to applications.
Based on the new requirement, we remove `r->target` rewritting
in the rewrite module.

Closes: nginx#916
hongzhidao added a commit to hongzhidao/unit that referenced this issue Apr 17, 2024
Previously, the REQUEST_URI within Unit could be modified,
for example, during uri rewritting. We plan to make $request_uri
immutable and pass constant REQUEST_URI to applications.
Based on the new requirement, we remove `r->target` rewritting
in the rewrite module.

Closes: nginx#916
@ac000 ac000 modified the milestones: 1.32, 1.33 Apr 18, 2024
hongzhidao added a commit to hongzhidao/unit that referenced this issue Apr 30, 2024
Previously, the REQUEST_URI within Unit could be modified,
for example, during uri rewriting. We decide to make $request_uri
immutable and pass constant REQUEST_URI to applications.
Based on the new requirement, we remove `r->target` rewriting
in the rewrite module.

Closes: nginx#916
hongzhidao added a commit to hongzhidao/unit that referenced this issue May 7, 2024
Previously, the REQUEST_URI within Unit could be modified,
for example, during uri rewriting. We decide to make $request_uri
immutable and pass constant REQUEST_URI to applications.
Based on the new requirement, we remove `r->target` rewriting
in the rewrite module.

Closes: nginx#916
hongzhidao added a commit to hongzhidao/unit that referenced this issue May 8, 2024
Previously, the REQUEST_URI within Unit could be modified,
for example, during uri rewriting. We decide to make $request_uri
immutable and pass constant REQUEST_URI to applications.
Based on the new requirement, we remove `r->target` rewriting
in the rewrite module.

Closes: nginx#916
Reviewed-by: Andrew Clayton <a.clayton@nginx.com>
Signed-off-by: Zhidao HONG <z.hong@f5.com>
pkillarjun pushed a commit to pkillarjun/unit that referenced this issue May 29, 2024
Previously, the REQUEST_URI within Unit could be modified,
for example, during uri rewriting. We decide to make $request_uri
immutable and pass constant REQUEST_URI to applications.
Based on the new requirement, we remove `r->target` rewriting
in the rewrite module.

Closes: nginx#916
Reviewed-by: Andrew Clayton <a.clayton@nginx.com>
Signed-off-by: Zhidao HONG <z.hong@f5.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
z-bug 🐞 z-documentation-update-needed This type of issues likely have a link to an issue in the Unit Docs repo z-question z-roadmap
Projects
Status: 🚀 Released
Development

No branches or pull requests

5 participants