How to turn a PHP script into a proxy server? - php

We all know that HTTP uses port 80, what if i put my server's ip and the port 80 in the browser's proxy setting, will the browser sends the HTTP requests to my index.php which will fetch the website from server side and return response headers and body?
Thanks

Assuming you have Apache or such listening on port 80, your requests will be sent to the server on that port. You should probably enable mod_rewrite and redirect every incoming request into index.php, otherwise the server will look for the requested filename and return a 404. Then you should use cURL inside index.php and echo the raw results, headers included.
The performance of the whole thing may well be less than stellar, I think.

If you're on Apache, there's no point in using a PHP script as a proxy - Apache has a perfectly good proxy (mod_proxy) module already, which would also eliminate the overhead (and problems) of running everything through PHP.

Related

apache2/php container running behind reverse proxy not respecting forwarded port and proto in redirects?

I am using a modified version of the official docker library php:7.0.30-apache image behind a reverse proxy (traefik).
The modifications include an alteration of apache2 default serving port 80 to port 1025. (openshift won't allow root operations like opening ports inside a docker container below 1024)
Now when using redirects inside the container apache2 ignores the HTTP_X_FORWARDED_PORT header and redirects to the correct hostname with port 1025 added.
Example:
The application runs at http://www.app.com (port 80) publicly, internally at http://app.local:1025 and when doing header("Location: web"); it redirects to http://www.app.com:1025/web instead of http://www.app.com/web
I also noticed the following behavior: When using .htaccess files to redirect to https browsers display a "too many redirects error" because both HTTP_X_FORWARDED_PORT and HTTP_X_FORWARDED_PROTO are ignored.
What do I need to do for .htaccess and php header("Location: xyz"); redirects work and respect forwarded headers behind a reverse proxy?
I do understand that this is the correct behavior for the request coming from the reverse proxy to the apache host, I just need to configure apache2 to react to the request that was made to the reverse proxy instead.

Does Apache pass to PHP whether the port (:80) was explicitly requested?

It doesnt matter whether a resource was requested via mydomain.com OR mydomain.com:80(which is how some bots/spiders make requests): HTTP_HOST always shows up as 'mydomain.com' and there is no way for PHP to know whether the request included a :80 (2). This leads me to believe that Apache passes the exact same request to PHP whether the port is specified or not (an it makes sense).
The problem: I have the NewRelic PHP agent installed on this machine, and it reports to the NewRelic service, via a PHP auto_prepend_file used to name the applications separately(1), both mydomain.com and mydomain.com:80. These two are the same application showing up under two different names in NewRelic control panel, which is undesirable. Since the application name is set via PHP, how could mydomain.com:80 possibly be passed to the NewRelic API when the code setting the name can't even see whether the request explicitly defines :80? NewRelic support tells me that my code is passing the :80 to their API, and that's just not possible(2). Does Apache pass to PHP whether the port (:80) was explicitly requested or not?
1) if I don't use this file, every vhost on the server will report under the same generic 'PHP Application' name
2) SERVER_PORT will always be 80, whether explicitly invoked or not (unless of course it's an https or non standard port request, which is not what's being discussed here). In other words, I cannot use SERVER_PORT to filter requests that have the port explicitly defined because whether the request does or does not have an explicitly defined port is invisible to PHP.
Apache 2.2.15, mod_fcgid 2.3.7, PHP 5.3.3, Linux 2.6.32.60-40 x64, CentOS 6.4
HTTP_HOST is literally just the hostname, e.g. www.example.com, of the site you're accessing. If you want the port number that the request came in to, then there's $_SERVER['SERVER_PORT']
Browsers AND curl will strip the :80 from the host header when the port requested is the standard (port 80). Since I had not tested using a manually issued GET, I didn't see how could $_SERVER['HTTP_HOST'] include a port number. I found that it does, WHEN the port is included in the Host header (which makes sense, since the manual specifies that $_SERVER['HTTP_HOST'] is "Contents of the Host: header from the current request, if there is one.")
Section 14.23 of the HTTP spec states that the port # should be included in a request IF its not the default port of 80. But it doesn't say whether it's OK or not to include the port number when the port used IS the default.
In my case, the requests that do include the port number, even when using the default port, came from the Baidu Spider.
If you need to see this by yourself, you need to issue a manual GET request. Use Netcat or Telnet to send these commands:
$ telnet www.host.com 80
GET /host.php HTTP/1.1
Host: www.host.com:80
Connection: close
(add two CRLFs at the end)

https:// link goes to :443 by itself

I have a few links in my page. When I open the page in http://, it works just fine (correctly goes to http://www.example.com/path/to/page. But when opened in https://, when I click on the link, it brings me to www.example.com:443/path/to/page instead, and it gives me a 400 error:
Bad Request
Your browser sent a request that this server could not understand.
Reason: You're speaking plain HTTP to an SSL-enabled server port.
Instead use the HTTPS scheme to access this URL, please.
I'm sure my link targets are fine (I use relative paths). How can I tackle this issue?
Default port for HTTPS is 443, because of which all calls to HTTP will route to http:/XYZ:443/ by default. If you want to access the url via https, you'd need to enable/setup https in your webserver.
If you are using apache, try this link: http://docs.oracle.com/cd/A95431_01/install/ssl.htm
Have you got SSL certificate four your domain or localhost?
"You're speaking plain HTTP to an SSL-enabled server port." Try to change your SSL settings.

HTTPS Header Redirect Not Working with PHP

I have a load balanced dev site that I'm working out bugs for SSL on and I have ran into one last very annoying issue. On some pages I need to force it to SSL so easy enough, I just wanted to create a
header ("Location: https://www.example.com/mypage.php");
I thought that was easy enough and no worries. However, every time I do this it transforms it back to http. Well as you can figure it creates an endless loop that can't be resolved. I can't figure out how to keep that https in there so that it will pull the secure version of the page. If I navigate directly to the secure page with https it works just fine. The only issue is on this redirect.
Any help would be awesome! I'm using POUND as a load balance proxy. Apache on the web-server nodes. The SSL cert is setup at the Load Balancer.
When loadbalancing, 'internal' SSL usually goes out the door: Clients connect through a load-balancer with which you can do SSL encryption, but behind that in most loadbalancers I've seen is plain 'HTTP'. Try to get your loadbalancer to set a custom header to you indicating that there is a HTTPS connection between loadbalancer & client.
From http://www.apsis.ch/pound/index_html
WHAT POUND IS:
...
an SSL wrapper: Pound will decrypt HTTPS requests from client browsers and pass them as plain HTTP to the back-end servers.
And from more manual pages:
HTTP Listener
RewriteLocation 0|1|2
If 1 force Pound to change the Location: and Content-location:
headers in responses. If they point to the back-end itself or to
the listener (but with the wrong protocol) the response will be
changed to show the virtual host in the request. Default: 1
(active). If the value is set to 2 only the back-end address is
compared; this is useful for redirecting a request to an HTTPS
listener on the same server as the HTTP listener.
redirecting to https pages is no problem.
you can check for the port, scheme or server variable (probably server variable is the best) to see if https is on, and have it as a condition for redirecting
$_SERVER['SERVER_PORT'] == 443
parse_url($_SERVER['REQUEST_URI'],PHP_URL_SCHEME) == 'https'
$_SERVER['HTTPS'] == 'on'
but as you have an infinite loop there must be something else wrong!
try using the load blancer "balance" instead. it only takes about 5 minutes to set up, and instead of proxying, will do "real" load balancing. I would guess your proxy is currently redirecting https requests to the http address. Try making a request without using the balancer. you can do this by setting up the host name in your /etc/hosts file to point directly to a server instead of to the load balancer's IP

Detecting HTTPS requests in PHP

The problem that I am having has to do with the need to keep some urls of a website protected by HTTPS and the rest kicked to HTTP.
Normally, you have $_SERVER['HTTP_HTTPS'] or $_SERVER['HTTPS'] (depending on your flavor of Apache). You also can check the port - it's 80 for normal traffic and 443 for HTTPS.
My problem is that the certificate sits on the loadbalancer, and all these variables are unavailable, and the webserver sees http://www.foo.com on port 80. One way to fix this is to tell the loadbalancer to send the traffic on a different port, but I wonder if there are other ways to detect HTTPS coming from the load balancer?
If anybody has the same issue behind an Amazon AWS Elastic Load Balancer, the solution is simple because the $_SERVER variable will include:
[HTTP_X_FORWARDED_PORT] => 443
[HTTP_X_FORWARDED_PROTO] => https
So, to get the protocol, you could use:
function getRequestProtocol() {
if(!empty($_SERVER['HTTP_X_FORWARDED_PROTO']))
return $_SERVER['HTTP_X_FORWARDED_PROTO'];
else
return !empty($_SERVER['HTTPS']) ? "https" : "http";
}
If the load balancer is the other end of the SSL connection, you cannot get any more info than the load balancer explicitly provides. I would go for adding a http header, it may already be doing that, dump all the HTTP headers and look.
As another solution, you can do the redirection on the load balancer based on URL.
the $_SERVER['HTTP_X_FORWARDED_PROTO'] seems to be a good solution for joomla users because if your loadbalancer does the rediretion and you set the force_ssl setting to 1 or 2 then you will end in an infinite loop because joomla always sees http:

Categories