0

I am trying to move my local testing site into a docker container for ease of use when changing between machines. I am using caddy within docker so that I can connect to the locally hosted site via https.

It is all working well except for the fact that cakephp uses the php $_SERVER['HTTPS'] variable when creating links using Router::url. Since caddy creates a reverse proxy on port 80 to the php server, the $_SERVER variables 'SERVER_PORT' and 'HTTPS' in php are being set to 80 and null respectively, even when the original request was made out to an https:// url.

How can I get the php $_SERVER variables 'SERVER_PORT' and 'HTTPS' to reflect the values in the original request (pre-proxy).

Options I have considered:

  1. Overriding and hard coding the environment variables which php uses for 'SERVER_PORT' and 'HTTPS'.
  2. Making the caddy reverse proxy connect to the php server on port 443
  3. Working out whether the request was made via https by looking at the url (or some other method)

The issue with first 2 options is that if a request is made via the http protocol php will believe it was made via https posing a security issue (and opening us up to annoying bugs when pushing to production).

The issue with the final option is that I don't want to screw around with the cakephp framework too much and there and this is likely not the only part of the website which uses these variables. It could also make future development a pain for developers who are not aware of the issues with using those server variables.

My setup (simplified):

Caddyfile:

local.site.com {
    tls internal
    reverse_proxy myWebsite:80
}

docker-compose.yml:

version: '3.8'
services:
  caddy:
    image: caddy:2-alpine
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./caddy/data:/data
      - ./caddy/config:/config
    ports:
      - '80:80'
      - '443:443'

  myWebsite:
    depends_on:
      - caddy
    build: .
    volumes:
       - /path/to/websiteCode:/var/www/html

Dockerfile:

FROM php:7.0-apache

Any help and advice is appreciated! Thanks.

Henry Howeson
  • 677
  • 8
  • 18

1 Answers1

0

Ok, so as far as I can tell there is no perfect solution. If you have anything better than this then please write an answer.

Option 1 (.htaccess solution):

Add the following to your .htaccess (apache webservers only)

SetEnvIf X-Forwarded-PROTO "https" HTTPS=on

In php $_SERVER['HTTPS'] should now be populated appropriately. As far as I know there is no way to do this for $_SERVER['SERVER_PORT'].

Note: The value of X-Forwarded-PROTO could be spoofed so don't rely on this in production unless you actually have a proxy server of some sort and it doesn't let users spoof this header.

Option 2 (cakephp 2.x solution):

Add the following code to app/config/bootstrap.php
This code will check to see if any headers are set that indicate https is enabled and will set the fullBaseUrl appropriately. This will fix the issue with the cakephp Router::url function but does not affect the server variables.

Note: Again, the headers used can be spoofed so only use it in production if you have a proxy server which doesn't pass through user generated "forwarded" headers.

if (
    (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== 'off') ||
    (!empty($_SERVER["HTTP_X_FORWARDED_SSL"]) && $_SERVER["HTTP_X_FORWARDED_SSL"] !== 'off') ||
    (!empty($_SERVER["HTTP_X_FORWARDED_PROTO"]) && $_SERVER["HTTP_X_FORWARDED_PROTO"] === 'https')
) {
    $scheme = 'https://';
} else {
    $scheme = 'http://';
}
        
Router::fullBaseUrl($scheme.$_SERVER['HTTP_HOST']);

Alternatively you could choose to always create links with the https:// scheme:

Router::fullBaseUrl('https://'.$_SERVER['HTTP_HOST']);
Henry Howeson
  • 677
  • 8
  • 18