laravel / valet

A more enjoyable local development experience for Mac.
https://laravel.com/docs/valet
MIT License
2.49k stars 690 forks source link

Redirect issue with Wordpress/Valet Share #274

Closed zacksmash closed 7 years ago

zacksmash commented 7 years ago

I have a Wordpress site that has the Front Page set to a static page. This causes the valet share ngrok.io URL to timeout from too many redirects, when viewed from a phone/tablet. Is there anything I can do to make this work?

The terminal spits out a ton of 301 permanent redirects when I try to hit the URL.

austenc commented 7 years ago

@zacksmash Did you ever figure out a workaround for this? It would be awesome to get this working.

zacksmash commented 7 years ago

@austenc haven't heard anything, which is kind of a bummer.

rumur commented 7 years ago

I've tried to share the project with static HTML file and got the same issue. 02-17-qtd12

maiorano84 commented 7 years ago

Just to shed some light on this:

This does not appear to be a Valet issue, but rather a Wordpress issue. The problem stems from the fact that Wordpress itself stores all of its URLs as database entries, and keeps trying to redirect based on the siteurl and home entries under the wp_options table (or prefixed equivalent).

If you're using a vanilla installation of Wordpress, then you might want to consider temporarily adding the following to your wp-config.php file, and then commenting them out when you're done sharing:

define('WP_HOME', 'http://{temporary-id}.ngrok.io/');
define('WP_SITEURL', 'http://{temporary-id}.ngrok.io/');

This will override your database entries without having to use a find-replace tool to change them.

If you're using Bedrock, then you can temporarily change your .env file to reflect the new path:

WP_HOME=http://{temporary-id}.ngrok.io/
WP_SITEURL=${WP_HOME}/wp

Hopefully this helps you, but unfortunately, I don't think this is something that Valet can fix.

zacksmash commented 7 years ago

@maiorano84 I have those entries in thewp-config.php or .env file, already. I do that because it makes it easier to work on a WordPress site locally. So, I don't think it's an issue with reading the URL from the wp_options table, because none of my sites do that. It only seems to be an issue when you switch your site to a static Front Page. If you leave it at the default, which is showing the blog on the home page, it works just fine.

maiorano84 commented 7 years ago

@zacksmash I get what you're saying now. Sorry about that.

That's interesting. Tested this against my own installation and used Browserstack to navigate to the public URL. Took a bit to connect, but I'm not seeing anything odd.

Are you able to replicate this behavior on a fresh Wordpress/Bedrock instance? I'd like to follow along with your steps and see if I can get the same results.

zacksmash commented 7 years ago

@maiorano84 Yes, I can replicate it every time.

  1. Create a wordpress directory mkdir wordpress && cd wordpress
  2. Create a new Wordpress site wp core download
  3. Install Wordpress site by going to wordpress.dev/wp-admin
  4. Update your wp-config.php file with define('WP_HOME', 'http://wordpress.dev') and define('WP_SITEURL', WP_HOME)
  5. Login and go to Appearance > Customize and change the Static Front Page to 'Sample Page'
  6. In terminal, run valet share from your wordpress directory
  7. Visit the ngrok.io URL and watch your terminal 301, multiple times
maiorano84 commented 7 years ago

@zacksmash Well, as mentioned before, your step 4 appears to be wrong.

WP_HOME shouldn't be http://wordpress.dev. It should be the ngrok URL, as I had said earlier:

If you're using a vanilla installation of Wordpress, then you might want to consider temporarily adding the following to your wp-config.php file, and then commenting them out when you're done sharing:

define('WP_HOME', 'http://{temporary-id}.ngrok.io/');
define('WP_SITEURL', 'http://{temporary-id}.ngrok.io/');

To confirm, I've followed your steps exactly to replicate the behavior you're seeing:

  1. Create a wordpress directory mkdir wordpress && cd wordpress
  2. Create a new Wordpress site wp core download
  3. Install Wordpress site by going to wordpress.dev/wp-admin
  4. Update your wp-config.php file with define('WP_HOME', 'http://wordpress.dev') and define('WP_SITEURL', WP_HOME)
  5. Login and go to Appearance > Customize and change the Static Front Page to 'Sample Page' In terminal, run valet share from your wordpress directory
  6. Visit the ngrok.io URL and watch your terminal 301, multiple times

Your problem is in step 4. I was able to fix this behavior by changing WP_HOME to the Ngrok URL:

http://b7572a87.ngrok.io/

I'll leave mine up for a few minutes so you can see for yourself. EDIT: Disabled as I need to pack up everything and head home.

zacksmash commented 7 years ago

@maiorano84 I guess that's where I'm confused, since you said that the reason for that was because it was trying to read it from the database. It's not, because I'm defining it in the wp-config file. So, maybe you could clarify what you think the issue is. I don't think I should have to change it to the ngrok URL, since I don't have to in any other framework.

maiorano84 commented 7 years ago

So, maybe you could clarify what you think the issue is

@zacksmash Dude, I literally gave you the answer. Twice.

The bottom line is that the Ngrok URL and the WP_HOME URL results in a mismatch, regardless of whether or not your home url is defined in the database or in your wp-config file. When you set a Front Page in your options, Wordpress will automatically redirect the site if the WP_HOME setting doesn't match the requested domain and it results in an infinite loop.

Change the URL in your define call when you share your site:

define('WP_HOME', 'http://{temporary-id}.ngrok.io/');
define('WP_SITEURL', 'http://{temporary-id}.ngrok.io/');

.... and then change it back to your local domain when you're done. That's the simplest confirmed working solution I can give you.

I don't think I should have to change it to the ngrok URL, since I don't have to in any other framework.

I'm sorry, and I don't mean to come across as a jerk when I say this, but it really doesn't matter if you think you should or shouldn't have to do something that fixes your problem. This is how Wordpress works, and the above notes that I've made ad nauseam corrects these caveats that come with this particular CMS.

What you're seeing is not the fault of Valet or NGrok. This is the fault of an overly complex system of procedural spaghetti that is long overdue for a code overhaul that adheres to modern development practices.

Any other local development tunneling system (ie: Vagrant Share) would yield similar results with Wordpress.

Still don't like it? Then report it as a bug to Wordpress.

If they won't budge on fixing their code to fit modern development practices, maybe you should try checking out Bolt.

Hopefully this helps, but I can't really offer much beyond this. Good luck.

zacksmash commented 7 years ago

@maiorano84 haha k.

zacksmash commented 7 years ago

So, for anyone who needs an actual fix for this issue, you can ignore everything previous to this comment which involves constantly and annoyingly updating your wp-config.php file.

What you'll want to do is update your wp-config.php file ONCE with the following.

define('WP_HOME', 'http://' . $_SERVER['HTTP_HOST']);
define('WP_SITEURL', WP_HOME);

Edit: You're still able to reach your local site at your regular valet .dev domain.

Make sure you remove this for production, or use a wp-config-local.php file for different environments.

For redundancy, you can choose to install a WordPress plugin that forces relative URLS, like this one. Again, remove this for production.

Otherwise, run valet share and off you go.

maiorano84 commented 7 years ago

So, for anyone who needs an actual fix for this issue, you can ignore everything previous to this comment which involves constantly and annoyingly updating your wp-config.php file.

Very mature.

I suppose setting any requested URL as your WP_HOME will be fine for people who don't mind running into bugs every time they mistype their URL and save new content.

But what do I know? I only identified the issue for you.

zacksmash commented 7 years ago

I only identified the issue for you.

Except you didn't. You turned into a diva and gave a half-assed, poorly researched answer and acted like it was gospel.

Very mature.

Says the 'mature' person who gave my much better solution a thumbs down. haha

joshmanders commented 7 years ago

Ok guys, lets just hug this out.

maiorano84 commented 7 years ago

I..... could use one.

:(

nicgutierrez commented 6 years ago

I came here with the same problem. Although I didn't manage to fix it, I'm happy to say that this thread was very entertaining!

Thank you @maiorano84 and @zacksmash 😆

rmenner commented 6 years ago

Found a solution that has the best of both worlds. Wrap it all up in a conditional and you're all set. Hope this helps.

if ($_SERVER["HTTP_X_FORWARDED_HOST"]):
define('WP_HOME', 'http://' . $_SERVER["HTTP_X_FORWARDED_HOST"]);
define('WP_SITEURL', WP_HOME);
endif;

I would still recommend you take this out of production but in theory this would not cause any issues. Thanks for helping me figure this out @maiorano84 and @zacksmash

Happy Valet share everybody!

P.S. I was having issues with my CSS not loading on my iPhone. After this fix no issues!

jnaklaas commented 5 years ago

Trying this in a fresh Bedrock Sage 9 install, and the provided solution doesn't appear to be working for me.

Using the development url as WP_HOME value in the .env file, makes the URL's absolute so css, images and js are not loading when viewing on an external device.

WP_HOME=http://mysite.localhost

Changing the WP_HOME value to the ngrok url, returns errors in the browser.

WP_HOME=http://{temporary-id}.ngrok.io

iOS safari complains about too many redirects, Firefox also says it's redirecting improperly.

antonhedling commented 4 years ago

I also had issues with this using Sage 9 & Wordpress 5.2. After debugging I found that the method redirect_canonical is responsible for the endless redirect chain. You can inspect the file wp-includes/canonical.php, but essentially it sets a variable _$redirecturl to the _$_SERVER['HTTPHOST']. This variable wont be the forwarded host. It then compares this to the site url which obviously will differ, therefore triggering the redirect.

Anyways, a seriously ugly hack is to override the _$SERVER['HTTPHOST'] variable. I added this to my config/environments/development.php:

if ($_SERVER["HTTP_X_FORWARDED_HOST"]) {
    Config::define('WP_HOME', 'http://' . $_SERVER["HTTP_X_FORWARDED_HOST"]);
    Config::define('WP_SITEURL', Config::get('WP_HOME'));
    $_SERVER['HTTP_HOST'] = $_SERVER["HTTP_X_FORWARDED_HOST"]; // Valet share hack
}

If someone figures out a nicer solution that would be great.

raptor235 commented 4 years ago

Found the problem this morning in core... redirect_canonical uses home_url() which then uses get_home_url() ...

get_home_url() doesn't look at WP_HOME constant at all..

No idea why they're bypassing it.


So in my case for anyone in the future the problem lay with https... for some reason my server wasn't returning is_ssl to be valid so it would try to redirect to http version of ngrok... and it would get stuck in a loop...

and thanks @antonioribeiro the $_SERVER['HTTP_HOST'] definition was the other big issue in my config... you have to overwrite that with the ngrok url... in my case my final config looks as follows

$_SERVER['HTTPS'] = 'on';
define('WP_SITEURL', 'https://' . $_SERVER['HTTP_X_ORIGINAL_HOST']);
define('WP_HOME',    'https://' . $_SERVER['HTTP_X_ORIGINAL_HOST']);
$_SERVER['HTTP_HOST'] = $_SERVER["HTTP_X_ORIGINAL_HOST"]; // Valet share hack
onlinelaser commented 4 years ago

Just to add to this, I found that I also had to add 127.0.0.1 as the first DNS entry in Network preferences as well as the config.php updates posted above - there are several other issues around the 127.0.0.1 requirement that helped me figure this out.

djmtype commented 3 years ago

if ($_SERVER["HTTP_X_FORWARDED_HOST"]): define('WP_HOME', 'http://' . $_SERVER["HTTP_X_FORWARDED_HOST"]); define('WP_SITEURL', WP_HOME); endif;

That didn't work for me here. I got this:

Too Many Connections Too many connections! The tunnel session 'ts_1sdIEKFNWOZ4DJD861TC5adK7iN' has violated the rate-limit policy of 20 > connections per minute by initiating 64 connections in the last 60 seconds. Please decrease your inbound connection > > > volume or upgrade to a paid plan for additional capacity.

The error encountered was: ERR_NGROK_702

roelti commented 2 years ago

The solution didn't work for me either. However when doing valet secure first, it did work. I'm using a Bedrock setup:

  1. valet secure in the folder I want to share
  2. valet share --region=eu (leave the --region argument if you're not in the EU).
  3. In the .env:
    WP_HOME=https://{temporary id}.ngrok.io
    WP_SITEURL=${WP_HOME}/wp
creativecoder commented 1 year ago

This problem does indeed happen within redirect_cannonical, when using a reverse proxy, specifically when visiting the home page of the site.

Thankfully, the result of that function is filterable. Here's my workaround: add the following filter callback (I put this code in a mu-plugin, like wp-content/mu-plugins/0-local.php). This will cancel the redirect if a reverse proxy/share domain (like ngrok.io) is being redirected to itself.

add_filter( 'redirect_canonical', function( $redirect_url, $requested_url ) {
    $redirect_host  = wp_parse_url( $redirect_url, PHP_URL_HOST );
    $requested_host = wp_parse_url( $requested_url, PHP_URL_HOST );

    if (
        // Is redirecting to the reverse proxy host,
        $_SERVER['HTTP_X_FORWARDED_HOST'] === $redirect_host &&
        // and is requesting the local (valet) domain.
        $_SERVER['HTTP_HOST'] === $requested_host
    ) {
        return false;
    }

    return $redirect_url;
}, 10, 2 );

For context, I'm also using this config in wp-config.php, to dynamically populate the site url settings with the reverse proxy or the local url, depending on what's being used for the request.

// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact
// see also https://wordpress.org/support/article/administration-over-ssl/
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && strpos( $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https' ) !== false ) {
    $_SERVER['HTTPS'] = 'on';
}

// Set SITEURL and HOME using a dynamic protocol.
define( 'REQUEST_ORIGIN', ( ! empty( $_SERVER['HTTPS'] ) ? 'https://' : 'http://' ) . ( ! empty( $_SERVER['HTTP_X_FORWARDED_HOST'] ) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : 'wordpress-develop.localhost' ) );
define( 'WP_SITEURL', REQUEST_ORIGIN );
define( 'WP_HOME', REQUEST_ORIGIN );