0

I have a Laravel 9.5 and there is an issue with the env variables.

In the project root folder, I have .env file and the content is:

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:key=
APP_DEBUG=true
APP_URL=https://liveurl.com

But when I run it with php artisan serve, the env variables are not read correctly.

I have a form

<form action="{{ route('adminlogin') }}" class="text-left" method="post">

but when it's rendered by the serve command, the action is:

<form action="http://localhost/login" class="text-left" method="post">

which is supposed to be https://liveurl.com/login

I have tried to run all the commands to clear cache, route, view, etc. but nothing helps.

php artisan cache:clear
php artisan view:clear
php artisan route:clear
php artisan route:cache

php artisan config:clear
php artisan config:cache
php artisan event:clear
php artisan event:cache
php artisan optimize:clear

php artisan clear-compiled && php artisan optimize

Can anyone help with this issue?

DreamBold
  • 2,727
  • 1
  • 9
  • 24
  • 1
    If you do `php artisan tinker`, then `dd(env('APP_URL'), config('app.url'))`, what do you see? All `.env` variables are passed to the various `config/*.php` files, including `APP_URL`, which should be in `config/app.php`, like `'url' => env('APP_URL', 'http://localhost')`. That's the first thing I can think of that would be mismatched. – Tim Lewis Mar 10 '23 at 17:55
  • 1
    They show up correct values @TimLewis – DreamBold Mar 10 '23 at 18:13
  • 1
    Hmm... So same behaviour on my local. I'm curious if `php artisan serve` simply doesn't use that `.env` or `config()` setting (I've never tried to use anything but the default `localhost`). I know it's used in some things like other `artisan` commands (i.e. `php artisan tinker` followed by `route('adminLogin')` should say `liveurl`) and Emails, so maybe `php artisan serve` simply ignores it, since you can change the URL via `php artisan serve --host=liveurl.com`, so maybe go with that in the meantime? – Tim Lewis Mar 10 '23 at 18:18
  • So I think it's more related to the route issue: `{{ route('adminlogin') }}"` it keeps `http://localhost/login` – DreamBold Mar 10 '23 at 18:19
  • It's very weird, even `route('adminLogin')` prints out the correct URL, but not in the blade template @TimLewis – DreamBold Mar 10 '23 at 18:21
  • Do you have `https://liveurl.com` in your browser URL or do you have `http://localhost`? – aynber Mar 10 '23 at 18:22
  • 1
    Again, it depends where. If you do `route('adminLogin')` in a `.blade.php` file, and render that via `php artisan serve`, it'll say `localhost`, unless you use that `--host` thing. If you do `php artisan tinker`, then `route('adminLogin')`, it should say `liveUrl`. – Tim Lewis Mar 10 '23 at 18:22
  • You gotta remember that `php artisan serve` is a wrapper that connects the specified URL (default of `localhost`, port `8000`) so you can access it in the browser. `APP_URL` is used for external things that would be running via a different process, like terminal commands (`tinker`, `schedule:run`, etc.) or Queues (redis, etc.), so the correct URL would be used. In a production environment, you'd have a real web server, associated with a purchased domain(s), that would serve your Laravel project differently (I'm not a DevOps guy, so that knowledge is outside my wheelhouse) – Tim Lewis Mar 10 '23 at 18:25
  • I have put the liveur.com on a server, aws @aynber – DreamBold Mar 10 '23 at 18:27
  • With `php artisan serve --host=liveurl.com` , can I pass https?? @TimLewis – DreamBold Mar 10 '23 at 18:28
  • I think so, but I would expect it to require additional configuration, since `serve` is a local command and you typically don't use `https` locally. I know it can be done, but you'd have to do some more research on the specifics. – Tim Lewis Mar 10 '23 at 18:57
  • It's running on docker on AWS, and we use `php artisan serve` to run the app in dockerfile – DreamBold Mar 10 '23 at 19:00
  • @dreambold if it's for production that's a very very bad idea. You also might need to trust proxies – apokryfos Mar 10 '23 at 21:58
  • is `php artisan serve` a bad idea? If so, what's the solution? – DreamBold Mar 10 '23 at 21:59
  • php artisan serve cannot handle more than 1 request at a time. Unless you have a lot of tiny containers (which is probably a bit wasteful) then you can't use it for a production app. Our laravel app is set up as: 1 nginx container, 1 php fastcgi container, 1 cron container and one container with supervisor running (for queue workers). The web requests go from an AWS load balancer to the nginx container which forwards PHP requests to the fast cgi container or serves static files itself. – apokryfos Mar 10 '23 at 22:08
  • There's a load balancer and the app is running in a docker container in AWS fargate, isn't it enough? – DreamBold Mar 10 '23 at 22:10
  • What would be the best approach you can recommend for the configuration? It would be welcome and helpful for the others coming here. @apokryfos – DreamBold Mar 10 '23 at 22:12
  • setting `APP_DEBUG=false` and then clear cache to see if it works? – OMi Shah Mar 11 '23 at 05:50
  • 1
    I don't know what the best approach is but [here](https://pastebin.com/TWsG34FD) is the dockerfile I use and [here](https://pastebin.com/BN2YR3dx) is my docker-compose.yml file and the nginx config is [here](https://pastebin.com/dKg9CwF0) (trimmed down a bit). My ECS task definition matches the docker-compose.yml as much as possible i.e. it has 4 containers all using the same image but running a different command. – apokryfos Mar 11 '23 at 08:01
  • You should also make sure you are using the [TrustProxies](https://github.com/laravel/laravel/blob/10.x/app/Http/Middleware/TrustProxies.php) middleware – apokryfos Mar 11 '23 at 08:08

2 Answers2

1

Based on your case, it is so weird laravel cannot change the base url dynamically of route() helper. after you change the APP_URL .env and clear the cache config.

Probably, I have some quick solutions for your case.

First, If you want to change your url from the config, just it to config/app.php

 'url' => env('APP_URL', 'https://liveurl.com')

I know, It's not quite good enough to hardcode, but it helps quickly.

Second, you can change the root url from AppServiceProvider, and still get dynamic from .env file.

Add 1 line code in app/Providers/AppServiceProvider.php.

Add this line in boot function:

public function boot(): void
{
    URL::forceRootUrl(config('app.url')); <-- add 
}

don't forget to add the class:

use Illuminate\Support\Facades\URL;

Note: Sometimes the Web Server has to restart

mozart
  • 71
  • 4
0

After much time spent digging into the issue, I finally found out the solution is forcing https for all URLs.

There are many approaches introduced, some of them are:

  1. Adding FORCE_HTTPS=true in the .env file (which didn't work for me)
  2. Adding URL::forceScheme('https') into app\Providers\AppServiceProvider.php file
namespace App\Providers;

use Illuminate\Support\Facades\URL; //--> Need to link this as well
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        URL::forceScheme('https');
    }
}
DreamBold
  • 2,727
  • 1
  • 9
  • 24
  • 1
    When using an AWS Load balancer, the SSL connection terminates at the load balancer and the connection between load balancer and application is over http. In order to generate correct links, the load balancer sends the X-Forwarded-Proto header to your application which needs to be read, which is why you will need to get the `TrustProxies` middleware to work in order to get the protocol and requested host correctly – apokryfos Mar 12 '23 at 10:10
  • Thank you for the following up, @apokryfos! I have set redirection from http to https in the load balancer, and https is linked to the app. Do I still need the `TrustProxies` middleware? I'm just asking because I thought my approach would work.. Any suggestions would be appreciated – DreamBold Mar 12 '23 at 15:52
  • 1
    Yes if you are behind a load balancer you do need a way to read the [`X-Forwarded-*`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded) headers. This is to be able to get the requesting user's IP and what protocol they made the request (in case you need them). Forcing https helps with the 1st part of that but if you implement rate limiting on IP you need the requesting user IP – apokryfos Mar 12 '23 at 17:07