Redirect http to https only works after page refresh Apache2

I have installed SSL Certificates on my website and on the domain.com everything works fine, meaning that typing domain.com redirects correctly to https://domain.com. However, I have installed a certificate for a subdomain as well such that the link becomes: subdomain.domain.com.

My goal is to have subdomain.domain.com redirect to https://subdomain.domain.com . This might sound weird but this semi-works meaning that when I first surf to subdomain.domain.com it uses the http protocol but when I refresh that same page it switches to https protocol.

This is my VirtualHost conf file (port 80):

<VirtualHost *:80>
  ServerName subdomain.domain.com
  ServerSignature Off
  
  ProxyPreserveHost On

  AllowEncodedSlashes NoDecode

  <Location />
    Require all granted

    ProxyPassReverse http://127.0.0.1:8181
    ProxyPassReverse http://domain.com/
  </Location>

  RewriteEngine on

  #Forward all requests to gitlab-workhorse except existing files like error documents
  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f [OR]
  RewriteCond %{REQUEST_URI} ^/uploads/.*
  RewriteRule .* http://127.0.0.1:8181%{REQUEST_URI} [P,QSA,NE]

  # needed for downloading attachments
  DocumentRoot /opt/gitlab/embedded/service/gitlab-rails/public

RewriteCond %{SERVER_NAME} =subdomain.domain.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

#RewriteCond %{SERVER_PORT} !443
#RewriteRule ^(/(.*))?$ https://%{HTTP_HOST}/ [R=301,L]

</VirtualHost>

I have removed to non related lines from this sample above. Here is the 443 conf file:

<    IfModule mod_ssl.c>
    SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
    <VirtualHost *:443>
      ServerName subdomain.domain.com
      ServerSignature Off
      
      ProxyPreserveHost On

      AllowEncodedSlashes NoDecode

      <Location />
        Require all granted

        #Allow forwarding to gitlab-workhorse
        ProxyPassReverse http://127.0.0.1:8181
        ProxyPassReverse http://domain/
      </Location>

      RewriteEngine on

      #Forward all requests to gitlab-workhorse except existing files like error documents
      RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f [OR]
      RewriteCond %{REQUEST_URI} ^/uploads/.*
      RewriteRule .* http://127.0.0.1:8181%{REQUEST_URI} [P,QSA,NE]

      # needed for downloading attachments
      DocumentRoot /opt/gitlab/embedded/service/gitlab-rails/public


    SSLCertificateFile /etc/letsencrypt/live/domain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/subdomain.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
    Header always set Strict-Transport-Security "max-age=31536000"
    SSLUseStapling on
    Header always set Content-Security-Policy upgrade-insecure-requests
    </VirtualHost>
    </IfModule>

Worth noting is that I am using certbot.

Hopefully someone can help me.

Your <VirtualHost *:80> configuration has a RewriteRule with a [P] flag. [P] implies [L] so Apache will ignore any subsequent RewriteRules, including the one below it that redirects to HTTPS.

You can fix it by removing the [P] rule from the <VirtualHost *:80> section, since it won’t be needed there when all that section is really doing is handling the redirect.

(So why does it work the second time? My guess is that even though you’re serving HTTP, maybe you’re requesting a subresource, such as an image or stylesheet, over HTTPS. If so, according to your configuration, that subresource will be served with a Strict-Transport-Security header, and once the browser sees that header on any HTTPS response, it will make all subsequent requests to that domain over HTTPS (until the max-age expires), whether the redirect is working or not.)

3 Likes

Thank you for the quick reply.

I tried what you suggested and changed:

  RewriteRule .* http://127.0.0.1:8181%{REQUEST_URI} [P,QSA,NE]

to

  RewriteRule .* http://127.0.0.1:8181%{REQUEST_URI} [QSA,NE]

After restarting Apache. And heading to subdomain.domain.com I a left with a error stating that it couldn’t connect to the server. After reloading that same page, it works.

Should I remove/change something in either of my *.conf files?

Sorry I should have been clearer, I meant remove the entire RewriteRule line containing the [P] flag, rather than remove the flag from the rule.

I have just removed the entire RewriteRule but unfortunately I am still stuck with the weird behavior as mentioned in my previous reply. For clearance

This is my port 80 configuration:

<VirtualHost *:80>
  ServerName subdomain.domain.com
  ServerSignature Off
  
  ProxyPreserveHost On

  AllowEncodedSlashes NoDecode

  <Location />
    Require all granted

    ProxyPassReverse http://127.0.0.1:8181
    ProxyPassReverse http://domain.com/
  </Location>

  RewriteEngine on

  #Forward all requests to gitlab-workhorse except existing files like error documents
  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f [OR]
  RewriteCond %{REQUEST_URI} ^/uploads/.*

  # needed for downloading attachments
  DocumentRoot /opt/gitlab/embedded/service/gitlab-rails/public

RewriteCond %{SERVER_NAME} =subdomain.domain.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

#RewriteCond %{SERVER_PORT} !443
#RewriteRule ^(/(.*))?$ https://%{HTTP_HOST}/ [R=301,L]

</VirtualHost>

Thanks in advance

You should also remove the two RewriteCond lines from above the now removed RewriteRule, though I don’t think that would cause the behaviour you describe. Did you remember to reload Apache after making that change?

Would you be willing to tell us your real domain name so that we can see what’s happening for ourselves rather than making possibly false assumptions?

It might also be worth temporarily disabling the Strict-Transport-Security header (by setting the max-age to 0) until you’ve got the redirect working, as otherwise it’s only going to confuse your testing.

Yes I have restarted apache2.

It seems to work now after disabling the two RewriteCond lines from above the RewriteRule and setting max-age to 0. I guess I could keep the settings the way they are now, since everything seems to work. What I am curious to know is whether disabling the RewriteCond, RewriteRule and setting max-age to 0 would be a bad thing to do?

Could you explain to me why disabling those lines actually made it work?

I will test this configuration by trying to open the website on a few devices. If it fails within the next few hours, I will share the full domain in this post.

It’s correct to disable the RewriteCond and RewriteRule. Disabling the RewriteRule was necessary as I explained above: since it had a [P] flag, it was preventing the rule below it (the redirect to HTTPS) from being processed. Once it was gone, I guess maybe the RewriteCond lines that had been above it were probably interfering in some other way with the redirect. I’m not sure exactly how, but generally any RewriteCond modifies the behaviour of the RewriteRule that follows it, and the next one was the redirect. In any case, the original purpose of those lines was to modify the behaviour of the RewriteRule that you removed, so once it was gone, they were also no longer needed.

Setting the max-age to 0 probably isn’t related to why it’s working now - I only suggested that to make testing easier. In this context the max-age represents how long the browser should remember to treat your domain as HTTPS-only. This could have made it difficult to tell, when you ended up on the HTTPS version of your site, whether that was because of the redirect or because of the Strict-Transport-Security header.

Now that the redirect is working you should be able to set it back to its original value, if you want to (though I’d recommend you finish your testing on those other devices first). It’s more secure to use a long max-age, since it makes it more difficult for users to unintentionally access your site over HTTP rather than HTTPS, or to click through browser security warnings about invalid certificates and such.

Thank you for your detailed explanation. So far it seems to be working as expected.

If anything occurs while this topic is still open, I will get back to it, otherwise I will open a new topic.

Again, @jmorahan thank you so much for your time and effort.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.