How to Redirecting HTTP to HTTPS, while terminating ssl via apache and varnish configuration

202 views Asked by At

I'm using virtualmin with apache. Configured varnish, and want to terminate ssl with apache. Apache is listening two ports 443 & 8080 varnish listening port 80

Error that I'm facing:

http to https redirect issue in apache sites. When request is https://example.com no issue, but when request is http://example.com, it doesn't redirects to https.

Here's my apache ssl config:

SuexecUserGroup "#1010" "#1006"
ServerName example.com
ServerAlias www.example.com
ServerAlias mail.example.com
ServerAlias webmail.example.com
ServerAlias admin.example.com
ServerAlias autoconfig.example.com
ServerAlias autodiscover.example.com

DocumentRoot /home/biolink/public_html

ErrorLog /var/log/virtualmin/example.com_error_log
CustomLog /var/log/virtualmin/example.com_access_log combined

ScriptAlias /cgi-bin/ /home/biolink/cgi-bin/
ScriptAlias /awstats/ /home/biolink/cgi-bin/
ScriptAlias /AutoDiscover/AutoDiscover.xml /home/biolink/cgi-bin/autoconfig.cgi
ScriptAlias /Autodiscover/Autodiscover.xml /home/biolink/cgi-bin/autoconfig.cgi
ScriptAlias /autodiscover/autodiscover.xml /home/biolink/cgi-bin/autoconfig.cgi

DirectoryIndex index.html index.htm index.php index.php4 index.php5

<Directory /home/biolink/public_html>
    Options -Indexes +IncludesNOEXEC +SymLinksIfOwnerMatch +ExecCGI
    allow from all
    AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
    Require all granted
    AddType application/x-httpd-php .php
    AddHandler fcgid-script .php
    AddHandler fcgid-script .php7.4
    AddHandler fcgid-script .php8.2
    FCGIWrapper /home/biolink/fcgi-bin/php7.4.fcgi .php
    FCGIWrapper /home/biolink/fcgi-bin/php7.4.fcgi .php7.4
    FCGIWrapper /home/biolink/fcgi-bin/php8.2.fcgi .php8.2
</Directory>

<Directory /home/biolink/cgi-bin>
    allow from all
    AllowOverride All Options=ExecCGI,Includes,IncludesNOEXEC,Indexes,MultiViews,SymLinksIfOwnerMatch
    Require all granted
</Directory>

RewriteEngine on
RewriteCond %{HTTP_HOST} =webmail.example.com
RewriteRule ^(?!/.well-known)(.*) https://example.com:20000/ [R]
RewriteCond %{HTTP_HOST} =admin.example.com
RewriteRule ^(?!/.well-known)(.*) https://example.com:10000/ [R]

SSLEngine on
SSLCertificateFile /home/biolink/ssl.cert
SSLCertificateKeyFile /home/biolink/ssl.key
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1

<Files awstats.pl>
    AuthName "example.com statistics"
    AuthType Basic
    AuthUserFile /home/biolink/.awstats-htpasswd
    require valid-user
</Files>

Alias /dav /home/biolink/public_html

<Location /dav>
    DAV on
    AuthType Basic
    AuthName "example.com"
    AuthUserFile /home/biolink/etc/dav.digest.passwd
    Require valid-user
    ForceType text/plain
    Satisfy All
    RemoveHandler .php
    RemoveHandler .php7.4

    RewriteEngine off
</Location>

<Location /git>
    DAV on
    AuthType Basic
    AuthName example.com
    AuthUserFile /home/biolink/etc/git.basic.passwd
    Require valid-user
    Satisfy All
    RedirectMatch ^/git$ http://example.com/git/gitweb.cgi
    RedirectMatch ^/git/$ http://example.com/git/gitweb.cgi

    RewriteEngine off
    AddHandler cgi-script .cgi
</Location>

SSLCACertificateFile /home/biolink/ssl.ca
RemoveHandler .php
RemoveHandler .php7.4
RemoveHandler .php8.2
IPCCommTimeout 2001

FcgidMaxRequestLen 1073741824
Redirect /mail/config-v1.1.xml /cgi-bin/autoconfig.cgi
Redirect /.well-known/autoconfig/mail/config-v1.1.xml /cgi-bin/autoconfig.cgi

ProxyPreserveHost On
ProxyPass / http://127.0.0.1:80/
RequestHeader set X-Forwarded-Port "443"
RequestHeader set X-Forwarded-Proto "https"

I used hitch to terminate ssl with below vcl config, it properly redirects to https - no issue. But with apache ssl termination, error of too many redirects loop.

VCL config:

sub vcl_recv {

if (std.port(server.ip) != 443) {
set req.http.location = "https://" + req.http.host + req.url;
return(synth(301));
}

    if (!req.http.X-Forwarded-Proto) {
        if(std.port(server.ip) == 443) {
            set req.http.X-Forwarded-Proto = "https";
        } else {
            set req.http.X-Forwarded-Proto = "https";
        }
    }

}
sub vcl_synth {

    if (resp.status == 301 || resp.status == 302) {
        set resp.http.location = req.http.location;
        return (deliver);
    }
}

Help me out in resolving my issue.

2

There are 2 answers

0
Daniel Ferradal On

Op says: When request is https://example.com no issue, but when request is http://example.com, it doesn't redirects to https.

As simple as adding a specific virtualhost for it:

<Virtualhost *:80>
ServerName example.com
ServerAlias www.example.com
ServerAlias mail.example.com
ServerAlias webmail.example.com
ServerAlias admin.example.com
ServerAlias autoconfig.example.com
ServerAlias autodiscover.example.com

RewriteEngine on
RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [R=301,L]
<Virtualhost>
0
PajE On

If i understand your configuration well, you have:

  • a varnish answering on HTTP 80
  • apache httpd answering on HTTPS 443

You want to have:

  • a cache on HTTPS contents via varnish
  • an hard redirect telling end-user to use HTTPS (i.e. a 301 someurl:80 to https://someurl:443)

in your case, on the varnish side you have

if (std.port(server.ip) != 443) {
set req.http.location = "https://" + req.http.host + req.url;
return(synth(301));
}

That tells varnish "if you're not answering on IP:443, redirects it to 443"

and then

    if (!req.http.X-Forwarded-Proto) {
      if(std.port(server.ip) == 443) {
        set req.http.X-Forwarded-Proto = "https";
      } else {
        set req.http.X-Forwarded-Proto = "https";
      }
    }

Telling varnish, "if the request is coming with x-forwarded-proto, considers it" But in your case, varnish should always answer on port 80, so only the 1st test is consider, so you might have endless loops.

Something like the following code for the VCL might do the job

sub vcl_recv {

  if (!req.http.X-Forwarded-Proto) {
    # the test might be useless
    # your varnish is probably configured to answer on 80 only
    # (and apache httpd on IP:443)
    if(std.port(server.ip) == 443) {
        set req.http.X-Forwarded-Proto = "https";
    } else {
        set req.http.X-Forwarded-Proto = "http";
    }
  }

  if (req.http.X-Forwarded-Proto != "https") {
    set req.http.location = "https://" + req.http.host + req.url;
    return(synth(301));
  }
}

sub vcl_synth {
  if (resp.status == 301 || resp.status == 302) {
    set resp.http.location = req.http.location;
    return (deliver);
  }
}