Rewrite url in Haproxy

I am using Haproxy Fastcgi to serve php files for wordpress. Static files are served by Nginx. Everything is working but the wordpress permlinks are not working. Here is my Haproxy config file

global
log /dev/log local0
user haproxy
group www-data

    # Default SSL material locations

defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http

frontend myproxy
bind :80
acl url_static path_end .gif .png .jpg .css .js
use_backend static if url_static
use_backend phpservers
default_backend phpservers

backend phpservers
use-fcgi-app php-fpm
server server1 /run/php/myapp.sock proto fcgi

backend static
server server2 /var/run/nginx.sock

fcgi-app php-fpm
log-stderr global
docroot /var/www/myapp
index index.php

Now wordpress works only when the url includes index.php. Without index.php the server returns 404 error.

I want to rewrite the url from

http://example.com/index.php/hello-world/

to

http://example.me/hello-world/

In nginx we use the below config to work

location / {
                
                try_files $uri $uri/ /index.php?$args;
        }

Is their any solution like this in Haproxy

It took me some time to find out, but I was successful with

  • setting the script name to index.php in the fcgi app with set-param SCRIPT_NAME /index.php unless the request did already contain a PHP file
  • since the admin backend has its own index.php in /wp-admin/index.php there needs to be a separate rule that sets the script name to that when we are accessing an admin URL unless the request did already contain a PHP file
  • doing nothing with the path in the frontend/backend

Full fcgi app:

fcgi-app wordpress
  docroot /var/www/html
  log-stderr global
  acl is_php path -i -m end .php
  acl is_admin path -i -m beg /wp-admin
  set-param SCRIPT_NAME /index.php unless is_php is_admin
  set-param SCRIPT_NAME /wp-admin/index.php if is_admin !is_php
  set-param HTTPS on

I was not successful with

  • using index. As the documentation states this appends the name after the path, so this won’t work
  • using path-info, this did nothing for me
  • doing something with http-request set-path ... as this changes the REQUEST_URI

What really helped me in finding the solution was adding a line in wp-config.php that prints out $_SERVER for every request. There you then see what values SCRIPT_NAME, REQUEST_URI and others have.

E.g. if you are running php-fpm in a container that logs to stderr you could add

$stderr = fopen( 'php://stderr', 'w' );
fwrite($stderr, print_r($_SERVER, true) . "\n");
fclose($stderr);
2 Likes

Cannot edit the above anymore. :roll_eyes:
Just to note that I had problems with the login and to solve that one should change the index.php set-param to set-param SCRIPT_NAME /index.php if !is_php !is_admin. Not 100% sure why the “unless” version has problems and the “if” version works, but that is what I saw.