Reputation: 2961
I like to run a Symfony 5 application behind a reverse proxy which supplies the following endpoint:
The proxy config basically is this:
ProxyPass /marketsy/ http://internal.service1/
On the server the reverse proxy is connecting to, I use the following apache rule for serving my Symfony application:
<VirtualHost *:80>
ServerName internal.service1
DocumentRoot /webroot/service1/public
<FilesMatch \.php$>
SetHandler proxy:unix:/run/php/php7.2-fpm-ui.sock|fcgi://localhost
SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
SetEnv HTTP_X_FORWARDED_PROTO "https"
</FilesMatch>
<Directory /webroot/service1/public>
AllowOverride None
Require all granted
FallbackResource /index.php
</Directory>
<Directory /webroot/service1/public/bundles>
FallbackResource disabled
</Directory>
</VirtualHost>
The application itself is reqachable but Symfony can't hanle the "service1" path prefix.
For example it tries to access the profiler under https://my.domain/_wdt/8e3926 instead of https://my.domain/service1/_wdt/8e3926 and beside the root route all the routing isn't working:
For example: When I try to access https://my.domain/service1/my/page i will get redirected to https://my.domain/my/page
Now my question is, how can I configure Symfony to know about the "service1" path prefix when generation urls ets.
Upvotes: 7
Views: 3456
Reputation: 1
Since Symfony 5.3 there is no need to modify the requests paths manually by an event subscriber or by changing route prefixes, as symfony now supports the X-Forwarded-Prefix
HTTP header. When the Reverse proxy pass this header to the symfony application, then the base URL of the Request object is correctly set and all generated paths get automatically prefixed.
In apache, you can use mod_header
to add the header, by adding a RequestHeader set X-Forwarded-Prefix "/marketsys"
(or like) directive to vhost configuration.
Be sure that X-Forwared-Prefix
is configured as trusted header, if you want to use this feature.
Upvotes: 0
Reputation: 2961
In addition to the solution @Jimmix provided, I had to write a subscriber to add a prefix to my request path:
<?php namespace My\Bundle\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class AppPrefixSubscriber implements EventSubscriberInterface {
/** @var string */
private $appPrefix;
public function __construct(?string $appPrefix) {
$this->appPrefix = $appPrefix;
}
/**
* Returns events to subscribe to
*
* @return array
*/
public static function getSubscribedEvents() {
return [
KernelEvents::REQUEST => [
['onKernelRequest', 3000]
]
];
}
/**
* Adds base url to request based on environment var
*
* @param RequestEvent $event
*/
public function onKernelRequest(RequestEvent $event) {
if (!$event->isMasterRequest()) {
return;
}
if ($this->appPrefix) {
$request = $event->getRequest();
$newUri =
$this->appPrefix .
$request->server->get('REQUEST_URI');
$event->getRequest()->server->set('REQUEST_URI', $newUri);
$request->initialize(
$request->query->all(),
$request->request->all(),
$request->attributes->all(),
$request->cookies->all(),
$request->files->all(),
$request->server->all(),
$request->getContent()
);
}
}
}
Upvotes: 1
Reputation: 6506
Proper way of doing it (example):
Create src/Controller/BarController.php
<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
class BarController
{
public function index()
{
return new Response('<p>Bar controler response</p>');
}
}
and src/Controller/FooController.php
<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
class FooController
{
public function index()
{
return new Response('<p>Foo controler response</p>');
}
}
Create config/routes/prefix-routes.yaml
index:
path: /
controller: App\Controller\DefaultController::index
bar:
path: /bar
controller: App\Controller\BarController::index
foo:
path: /foo
controller: App\Controller\FooController::index
and edit routing config/routes.yaml
- delete its contents and just put:
prefixed:
resource: "routes/prefix-routes.yaml"
prefix: service1
all of controllers are now available at urls:
http://localhost/service1/ for DefaultController.php
http://localhost/service1/bar for BarController.php
http://localhost/service1/foo for FooController.php
If you want your profiler to work with service1
prefix as well then edit config/routes/dev/web_profiler.yaml
this way:
web_profiler_wdt:
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
prefix: service1/_wdt
web_profiler_profiler:
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
prefix: service1/_profiler
now they should be available at:
http://localhost/service1/_wdt... for wdt
http://localhost/service1/_profiler for profiler
Adding prefix for annotations:
Create controller src/Controller/AnnoController.php
:
<?php
namespace App\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class AnnoController extends AbstractController
{
/**
* @Route("/anno", name="anno")
*/
public function index()
{
return new Response('<p>Anno controler response</p>');
}
}
edit config/routes/annotations.yaml
and add prefix: service1
:
controllers:
resource: ../../src/Controller/
type: annotation
prefix: service1
kernel:
resource: ../../src/Kernel.php
type: annotation
Now prefix is added to routes done via annotation:
http://localhost/service1/anno for AnnoController.php
Some references:
Symfony Routing Prefix
Symfony Routing Configuration Keys
Adding prefix quick and dirty workaround to add prefix service1
to all of routing (not recommended).
Instead of changing routing as above just Edit src/Kernel.php
protected function configureRoutes
and change every $routes->import
line by adding ->prefix('service1')
at the end so it looks this way:
protected function configureRoutes(RoutingConfigurator $routes): void
{
$routes->import('../config/{routes}/'.$this->environment.'/*.yaml')->prefix('service1');
$routes->import('../config/{routes}/*.yaml')->prefix('service1');
if (is_file(\dirname(__DIR__).'/config/routes.yaml')) {
$routes->import('../config/{routes}.yaml')->prefix('service1');
} elseif (is_file($path = \dirname(__DIR__).'/config/routes.php')) {
(require $path)($routes->withPath($path), $this);
}
}
all of controllers are now available at urls:
http://localhost/service1/ for DefaultController.php
http://localhost/service1/bar for BarController.php
http://localhost/service1/foo for FooController.php
as well as the profiler:
http://localhost/service1/_wdt... for wdt
http://localhost/service1/_profiler for profiler
Upvotes: 8