View Issue Details

IDProjectCategoryView StatusLast Update
0017737phpList 3 applicationInterface - Administratorpublic21-06-18 13:05
Reporternettrustnz Assigned To 
Status newResolutionfixed 
PlatformLAMPOSLinux Slackware64OS Version14.1
Product Version3.0.12 
Fixed in Version3.2.0 
Summary0017737: Campaign tabs not working with PHPList behind reverse proxy
DescriptionI am using an Apache/PHP web server with Nginx reverse proxy. When accessing the same PHPList installation directly, it works as expected.

When accessing it via an Nginx reverse proxy, only the first campaign tab (the default one) can be reached through the admin system. All other tabs do nothing - just refresh the first tab.

I can access any tab using the full URL.

Observing the HTTP headers with a browser plugin showed the browser was not including "&tab=XXX" in the GET request, and the Nginx/Apache setup was just honoring the request as sent.

This happened with both Firefox and Chromium.
Steps To ReproduceIn the admin section:

1. Campaigns
2. Send a campaign
Tab 1 (content) shows
3. Click any other tab

Works as expected when accessed directly through an Apache only virtual host, but not when Nginx is acting as a reverse proxy.
Additional InformationAll software versions used are current stable.



04-07-15 14:05

administrator   ~0056278

seems more like a badly configured proxy to me. If it doesn't pass on the parameters in the Query String, then phpList should be unusable completely, because that's how most pages work.


04-07-15 22:58

reporter   ~0056279

C&P from above "Observing the HTTP headers with a browser plugin showed the browser was not including "&tab=XXX" in the GET request, and the Nginx/Apache setup was just honoring the request as sent.".


05-07-15 11:28

administrator   ~0056280

C&P from above "When accessing the same PHPList installation directly, it works as expected. "


05-07-15 20:33

reporter   ~0056281

I don't know why PHPList has problems when behind a reverse proxy (when everything else works). I am posting up here what I have found in the hope of a resolution.

A Google search shows others with the same symptoms but as most people are using other's hosting, they are unlikely to be able to find where the problem lies and under what set of circumstances.

I have provided as comprehensive a description as I can (after several hours of investigation) and I ask this be taken seriously.


06-07-15 07:13

administrator   ~0056285

Last edited: 06-07-15 07:14

View 2 revisions

Yes, it's great to have closer access to such a system to allow diagnosis. But I'd need access to be able to help further. Trying to replicate the setup would be too time consuming. There's nothing I can think of that could cause this, apart from the proxy setup, as my first response.

Best would be to put in break points and see where the data is being changed and not as expected.

The main question is why is this only happening with the "tab=" parameter and not with any others. Maybe changing the param to "phpListTab" helps and "tab=" is a reserved word in the proxy ?

I've seen this in the past when "&perc=" parameters were interpreted as HTML characters (incorrectly, as they missed the ; to be "&perc;") and then turned into the percentage sign by browsers.


06-07-15 07:40

reporter   ~0056286

The setup uses Nginx 1.9.2 and Apache 2.4.12, which are both current versions. I have stuck with safe settings and all relevant proxy settings are practically default*. It is running a large (over 900 page) e-commerce site and other stuff with no issues.

*The only non-default setting I can see is it uses HTTP1.1, instead of HTTP1.0 behind the proxy.

I am an experienced SysAdmin and also have experience with coding, though PHPList is so large (and I have never gotten into it) it's a head scratcher for me. A Google shows others are having an issue with these symptoms but as they are not in the infastructure owners, they are unlikely to get to the bottom of it - if it is the same cause.

I have tested various Nginx configuration options with no success. But if you (or anyone else) can offer some specific points - especially if there is something 'weird and wonderful' about PHPList, I'm happy to check these out and report back.


06-07-15 07:59

administrator   ~0056287

in send.php line 115, write the following:


and then load




and then post the output here.


06-07-15 08:08

reporter   ~0056288

Using proxy and clicking on the following URL:

string(0) "" NULL

Note: When I mouseover the link it shows the full URL.

Using Apache directly and clicking on the following URL:

string(6) "Format" NULL

Note: Although bpth URL's are at different web addresses they are the same installation.


06-07-15 08:17

administrator   ~0056289

can you add "&phpListTab=YYY" to the URL ? The NULL is that one.


06-07-15 08:26

reporter   ~0056290

Using proxy and inserting following URL into address bar:

string(0) "" string(6) "Format"

Ditto, to Apache:

string(0) "" string(6) "Format"

To clarify the original issue report, when the full URL is used in the browser address bar, it works either way. It's only when clicking the tabs there is the difference. Either way the tab links to the full address (as seen in the browser status bar) but it only ends up at the right place when accessed directly at Apache. When proxied, it stays on the default tab (1 - content)


06-07-15 08:37

administrator   ~0056291

Yes, so, this experiment shows that the "tab=" is something that the proxy doesn't like, because phpListTab is getting through.

in send_core.php change every instance of




and line 42:

  $baseurl .= '&phpListTab='.$_GET['phpListTab'];

and every instance of




or alternatively, search the proxy documentation to find why it doesn't like "tab="


06-07-15 08:53

reporter   ~0056292

Interesting idea but I have just tried that with no improvement.


06-07-15 09:48

administrator   ~0056293

did you change line

that's the most important one.


06-07-15 09:50

reporter   ~0056294

Yes I did and the new file works in Apache.


06-07-15 10:17

administrator   ~0056295

well, it must be something like that. Without access, there's little I can do now.

the fact that $_GET['phpListTab'] works and $_GET['tab'] doesn't gives you a hint towards how to resolve it.


06-07-15 10:26

reporter   ~0056296

Could you please carefully re-read the original post. As I stated, right from the start, if all the GET query parameters are supplied in the address bar it works either way. If the link is clicked on it only works in the non-proxy setup.

Changing the GET parameters is a red-herring.


06-07-15 10:27

reporter   ~0056297

Typo correction:
Changing the name of the GET parameters is a red-herring.


06-07-15 10:36

administrator   ~0056298

Last edited: 06-07-15 10:37

View 2 revisions

are you sure ?

In 0017737:0056288 you report the result "" (empty string) and "Format" (on the first param)

In 0017737:0056290 you report the result "Format" and "Format". (on the 2nd param)

That's what I'm going on with my suggestions.

The thing you didn't try was to load


on both systems.

My expectation is that the result is:

string(0) "" string(6) "Format"


string(6) "Format" string(6) "Format"


06-07-15 11:14

reporter   ~0056300

I will respond to the above tomorrow as it's late at night here. In the meantime, can you please advise me if there is any part of the code which utilises the server name of the HTTP server? (For example: $_SERVER["SERVER_NAME"]) This is one obvious area which would cause issue in a reverse-proxied setup.


06-07-15 11:21

administrator   ~0056301

IIRC SERVER_NAME is not essential for anything. Maybe HTTP_HOST is. It may only be used to initialise things. But I have many setups with different domains pointing to the same installation, without any issue, so SERVER_NAME should not matter.

but it is used in some places.

fgrep -rl SERVER_NAME *


06-07-15 11:29

reporter   ~0056302

"But I have many setups with different domains pointing to the same installation, without any issue, so SERVER_NAME should not matter."

Yes, but for all intentional purposes, each invocation of the PHP script is relative to the host which executed it, so the variable will be appropriate for that host. This is not the case with a reverse-proxy. The front end host (what the client sees) and backend host (which calls the script) are often on different virtual host names.

Any script which uses virtual host name - especially if this is propogated to the client (for the client to rely on) is, by defintion, incompatible with a reverse proxy. If this is the case anywhere in PHPList - this should be fixed irrespective of this particular matter.


06-07-15 11:34

reporter   ~0056303

In my code - I hardcode the front end and backend virtual host names as config variables - but there should at least be an option to set the front end virtual host name. (The back end can be inferred with $_SERVER["SERVER_NAME"])


06-07-15 11:59

administrator   ~0056304

but that's a red herring again. IIUC. everything works, except the "tab=" param.


06-07-15 20:45

reporter   ~0056322

You are drawing conclusions from the results which are not there to draw. Although I have made it very clear the test conditions and the corresponding results - you keep trying to selectively interpret it to suit your narrative.

It has NOTHING to do with the name of the variable. It has to do with the test conditions and if you read the information I have provided, this will be a big help.

Regardless of the name of the variable, if it's manually entered in the URL bar - it works whether proxied or not. If it's clicked, it only works when directly served by Apache.

This was clearly explained in the original post and has been repeated throughout.

It is also disappointing you have dismissed my feedback on proper coding standards as a "red herring".


06-07-15 21:10

administrator   ~0056324

I think we are agreeing, but misunderstanding. I haven't used SERVER_NAME in code for the last 10 years. All references in phpList are relative. The grep above probably just found some comments in the code.

Can you explain your conclusions from your findings in

0017737:0056288 and 0017737:0056290

Your conclusions seem to be different from mine, provided you put in what I wrote in 0017737:0056287

I would still like to see the results from mailinglist/admin/?page=send&id=51&phpListTab=Format&tab=Format to have a final verdict on this, but yes, maybe I am fixed on a possible solution which is not going anywhere. At this stage I don't feel informed enough to be able to say that for sure. Generally, when solving a problem, you have a hunch, and then work to disprove it, in order to go on to the next hunch.

But if you write "if it's manually entered in the URL bar - it works whether proxied or not. If it's clicked, it only works when directly served by Apache. " then I'm puzzled. I don't see how clicking something is different from loading it manually, even behind proxies. I guess you being familiar with your setup should have a better idea on that. I'd appreciate to hear the solution when you find it.

I think this is as far as I can go without having access. I'm doing this with my eyes closed.


06-07-15 21:18

reporter   ~0056327

My initial hunch would be a Javascript issue and one of the early tests I did was to try another browser. I have tested with Firefox and Chromium - current versions.

To save me spending ages dissecting the code - please explain what happens when a user is at the default tab (#1 - content) and clicks another tab.

My opinion at this stage is it's most likely a Javascript issue or some part of that process which is incompatible with Nginx configuration. This assumption is based on eliminating server names as the issue (ie: there would be an obvious issue if the backend virtual host server name was propogated to the client and the client relied on this).


06-07-15 21:26

administrator   ~0056328

Try loading admin/?page=send and the switching off Javascript

I do that with the Web developer toolbar,

Switching between tabs still works. They are just other pages, served with HTTP(s).


06-07-15 21:27

reporter   ~0056329


In send.php:
include "send_core.php";


if ($done) {
  if ($GLOBALS["commandline"]) {

@Tab 1 - content:
NULL string(0) ""

Click on Tab 2 - Format:
URL in status bar:

URL it went to: (note the # at the end)
NULL string(0) ""

Enter your test URL into address bar:
string(6) "Format" string(6) "Format"

All above tests done with Proxy.


06-07-15 21:32

administrator   ~0056330

ah, but, you've got a point. There's a "save" in between when JS is enabled. Let me check this.


06-07-15 21:35

reporter   ~0056331

With Javascript turned off and clicking through the tabs - from left to right:

NULL string(7) "Content"
NULL string(6) "Format"
NULL string(6) "Attach"
NULL string(10) "Scheduling"
...etc. I assume the rest work.


06-07-15 21:42

administrator   ~0056332

the process, without JS is just like linking to other pages.

However, with JS the following happens:

1. the "tab" clicked on is stored in the "followupto" form variable
2. the form is submitted (and all data sent to the server)
3. the data is stored (so that switching tabs keeps data).
4. a redirect header (Location: ) is sent to the browser with the data from the "followupto" field

the validity of the followupto is checked with the HTTP_HOST header.

Maybe that helps to find the cause?


06-07-15 22:00

reporter   ~0056333

1. Are all the URL's in the JS relative?

2. Where is the host check and how do I disable it? *This* is a very real issue needing to be fixed.

Here is why (my setup in real life)

Website client sees:

Website on server:

PHP thinks it is:

This is a very standard type reverse proxy setup. One way around this is differentiating back end virtual hosts by port, instead of server name. But that is a poor substitute for coding to accommodate reverse proxies. It also defeats one of the major reasons form using a RP - load balancing.

I strongly recommend you have something like the following in your config.php:

$use_reverseproxy = true / false;
$reverseproxy_hostname = "";

or simply just do away with HTTP_HOST or SERVER_NAME and have something like this:

$virtual_hostname = "";

I await your response to the above info required and I will test and respond with my results.


06-07-15 22:07

reporter   ~0056334

opps typo: "It also defeats one of the major reasons for using a RP - ie: load balancing".


06-07-15 22:17

administrator   ~0056335

I guess you'd need to set it up so that

Website client sees:

Website on server:

HTTP_HOST on server is

What I still don't understand is that if the redirection is to why does it lose the "tab" param and not the "page" param. I can imagine it would wipe all parameters (eg go back to but not only some.


06-07-15 22:18

administrator   ~0056336

I can see an option to rewrite HTTP_HOST use into a configurable setting that defaults to HTTP_HOST.

That's quite a lot of changes though.


06-07-15 22:31

reporter   ~0056337

I will try and explain. The client thinks the proxy is the server, whereas the proxy merely acts as a client (In it's own right) to the server.

Therefore - it should NOT redirect to

As for a "lot of changes", well, that's how programming works. We learn a better way and use it. Relying on HTTP_HOST/SERVER_NAME for anything propogated to the client (or to test client responses - like redirect checks) usually works but it's not good practice.

If you can help me out here (so I don't have to trawl though code to work out how the system works) I will test this and get back.


07-07-15 07:03

administrator   ~0056338

yes, I'm familiar with proxies. That's why I wrote "HTTP_HOST on server is". I don't know where you read that I wanted it to redirect to

Open Source works by need. I'm hesitant to destabilise the code for this purpose at this stage. What you'd need to do is fork the code, and work on it until you have it stable, then PR it. As I cannot replicate the environment, it's more convoluted to stabilise it. I can do it for you, but at an hourly rate as any other contractor would.


11-07-15 06:20

reporter   ~0056389

I have done some more investigation and the problem lies in isValidRedirect()


11-07-15 07:14

reporter   ~0056390

The issue is in public_html/lists/admin/lib.php around line 920 where it uses $_SERVER["HOST_NAME"]

This needs an override in the config.php where a hostname can be manually set.

This will be trivial to code in but I will let you do this in the existing coding style.


11-07-15 07:59

reporter   ~0056391

Just to clarify - by manual host name override, this is the front end hostname which needs to be set.


11-07-15 11:13

administrator   ~0056393

is it just that one place that needs changing?

If you can hack it for your system and then report in a little while whether you've had any issues, that would be great. If you don't encounter issues, then the change will be trivial enough to make it a feature in the core code.


11-07-15 22:46

reporter   ~0056404

I restored back to the original versions of send.php and send_core.php and made the change to admin/lib.php.

I have already 'hacked' a change for my system.

I suggest this fix is implemented immediately as I can not see any downside to it. We know exactly why the code failed and what the dynamics of the problem are.

Or at least issue a diff patch which allows the hostname to be specified in the config.


13-07-15 16:19

administrator   ~0056417

would be great if you can test and verify this change. I think it's fine, but you never know for sure, until it's in place.


15-07-15 09:25

manager   ~0056440

Collecting feedback


15-07-15 09:45

reporter   ~0056441

Please advise - are the 5 modified files compatible with release 3.0.12 with no further files needed?


15-07-15 09:46

reporter   ~0056442

ie: no further file changes needed?


15-07-15 09:56

manager   ~0056443

looks like it to me :)


15-07-15 10:07

administrator   ~0056444

no, it won't work to just replace those 5 files. Loads of other things have changed.

I will release an intermediate release today, which you can use


15-07-15 10:21

administrator   ~0056445

upgrade to this version:


15-07-15 10:36

reporter   ~0056447

Thanks for that. The version at the previous link was giving an HTTP500, but I have installed v3.1.2 and this seems to work. I will give it a better test tomorrow (It's late here) and get back asap.


15-07-15 23:09

reporter   ~0056451

The tabs work but it is returning 404 errors in various places. One of the scenarios is:
1. Click "start a new campaign" in the section "list of campaigns".
2. 404 returned
3. Use page back and the page shows with the new campaign as a draft

I have flushed the browser cache and the issue remains.

HTTP server logs:
IP - - [16/Jul/2015:11:07:55 +1200] "GET /mailinglist/admin/?page=send&new=1&tk=e0bc1f0c3f2ca0df HTTP/1.1" 302 10461 "" "Mozilla/5.0 (X11; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
IP - - [16/Jul/2015:11:07:55 +1200] "GET /lists/admin/?page=send&id=55 HTTP/1.1" 302 230 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0" - - [16/Jul/2015:11:07:55 +1200] "GET /e404/page-not-found HTTP/1.1" 404 19374 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"


15-07-15 23:41

reporter   ~0056452

I have noticed the 'location' header redirects are specifying http when this should be configurable for http or https.


16-07-15 08:16

administrator   ~0056453

Last edited: 16-07-15 08:16

View 2 revisions

For the 404s you need to set the correct "$pageroot" in your config file

it sounds like you have put phpList on /mailinglist/ and not the standard /lists/
Did you set the "pageroot" to be /mailinglist/ ?

The protocol is picked up from the system, but can you outline your setup?

is it outside world -> SSL -> proxy -> Non-SSL -> Server?

In that case the Server is non-SSL, but the links need to be SSL. We will need to make that work as well.

You can change that here:

It allows setting PUBLIC_PROTOCOL, but that has a different function. That setting is when you have "admin" on SSL but want to have the public subscribe pages on Non-SSL.

In this place you can set

$GLOBALS['scheme'] = 'https';

and I will add a config that allows overriding the "auto-detection".


16-07-15 08:26

reporter   ~0056454

You are right about the $pageroot setting and I have fixed this.

Yes, the proxy also doubles as an TLS offloader.

I have PUBLIC_PROTOCOL set as https because the entire website is served over https.

Thanks for that and I think we are on the right track to having this one solved soon. I await advice of the further changed version and will test it + report back as soon as possible.


16-07-15 08:54

administrator   ~0056455

In a way, you won't need the admins to use the proxy to access it, which means that you can keep the admins to directly access the server, and you set the PUBLIC_PROTOCOL to be https

Would that work in your situation?


16-07-15 08:57

reporter   ~0056456

No, because I only use Nginx as a proxy and to serve static files. All PHP code is run by Apache.


01-10-15 09:42

administrator   ~0056927

Is this resolved with 3.2.0? I'm not entirely sure what the status is of this issue.


02-10-15 21:22

reporter   ~0056943

I am presently testing 3.2.0


29-10-15 00:37

reporter   ~0057105

Now testing 3.2.1

I can confirm there is still problems. When I update a user it updates in the DB, but browser returns 404.

To start off to confirm I have the config correct:

# In some systems (eg behind load balancing proxies) you may need to set the HOST to be something else
# then the system identifies. If you do, you can set it here.


29-10-15 00:44

reporter   ~0057106

Sorry, please disregard the last post. I have just noticed my $pageroot was set to default. I have now updated this and will advise in due course if I notice any further issues.


27-11-15 23:10

administrator   ~0057352

any feedback? Can this be closed?


27-11-15 23:16

reporter   ~0057353

I have not used it since upgrading to 3.2.3. When I have an answer I will revert back.


10-11-17 16:20

reporter   ~0059656


I think I have the same problem.
This works with a direct connection to the server.

But in production through a reverse proxy with nginx, I can't initiate the database, and have some other troubles ..

I'm not sure how to figure out the function
define('HTTP_HOST',''); should be the public url acces ? maybe with https ?

or is it the local network address (I never see something like that)?

Both didn't work for me, is it possible to have a exemple