1

I have setup https on apache configuration of my website.conf as

<VirtualHost *:5061>
    <Directory/var/www/website.com>
    SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
    <Directory>
    ServerName website.com
    ServerAlias website

    SSLEngine on
    SSLCertificateKeyFile /etc/certs/website.key
    SSLCertificateFile /etc/certs/website.crt
    SSLCertificateChainFile /etc/certs/website.bundle
<virtualHost>

and the above being hosted on 5061 port are REST API services I want anyone attempting to reach the ServerName over http should be redirected to https without the port change .

is this possible ?

5
  • 2
    you can't run http and https on the same port. Nov 21, 2018 at 6:57
  • so what should I do clients still attempting to reach the same end point on http ?
    – Chang Zhao
    Nov 21, 2018 at 7:16
  • 2
    use a different port for https and redirect there. Nov 21, 2018 at 7:18
  • @GeraldSchneider: One could in theory run http and https on the same port since in both cases the client sends the first application payload and it is easy to find out from the first bytes if this is plain HTTP request or a TLS ClientHello. But, this is neither supported by Apache nor nginx nor most other servers. nodejs with the right module can actually do it. Nov 21, 2018 at 9:58
  • 2
    I feel that it is quite a shame for a mature web servers not capable of doing it !
    – Chang Zhao
    Nov 22, 2018 at 9:38

3 Answers 3

2

The standard practice is to redirect HTTP connections to the HTTPS port. You cannot host both HTTP and HTTPS on the same port on the same server, without a lot of additional setup, as stated by Gerald and Steffen above.

Why do you want to avoid redirecting to the correct port? Is it breaking a specific implementation you need? It is an odd scenario wherein clients are ignorant of the need for SSL, but need to use it, and can only access the server via a single port. Not saying such a scenario doesn't exist, of course.

Apache Virtualhost SSL redirect example:

NameVirtualHost *:80
<VirtualHost *:80>
ServerName www.example.com
Redirect / https://secure.example.com/
</VirtualHost>

<VirtualHost _default_:443>
ServerName secure.example.com
DocumentRoot /usr/local/apache2/htdocs
SSLEngine On
# etc...
</VirtualHost>

https://wiki.apache.org/httpd/RewriteHTTPToHTTPS

2

Contrary to popular belief it's actually quite easy to do this.

If you attempt to make a HTTP connection to an HTTPS port, Apache by default returns a "400 Bad Request" and an error page explaining that you need to use HTTPS to connect to the port. Therein lies your opportunity.

A single line of configuration in your vhost can replace that 400 with a 302 redirect telling the browser to reconnect to the same host and port but with HTTPS instead:

ErrorDocument 400 https://yourdomain:1000/

Note that this results in a 302 redirect, not a 301. A 301 is probably possible but the configuration would likely be more complex.

It's also a good idea to use HSTS so that once a browser has connected via HTTPS, for any future attempts that browser will automatically swap HTTP for HTTPS without having to hit your redirect again.

Also note that using this method, http://server:1000/something/ will redirect to https://server:1000/ (the root of the site). There are probably ways to work around this, however, if you use HSTS, once a browser has accessed the HTTPS site for the first time, it will automatically convert http://server:1000/something/ to https://server:1000/something/ going forward.

Here's a slightly more complex configuration that forces a 301 redirect instead of a 302, and makes an attempt to preserve the URI, although that part doesn't seem to actually work.

    ErrorDocument 400 /%{escape:%{REQUEST_URI}}
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^/?(.*) https://%{SERVER_NAME}:8181/$1 [R=301,L]

I think that since the "generate 400 when hitting HTTPS port with HTTP" thing is a bit of an obscure feature, Apache doesn't populate %{REQUEST_URI} as it normally does. In fact the requests always show up in the log as "GET / HTTP/1.0" regardless of what's actually being requested, and regardless that I'm using HTTP 1.1 instead of 1.0. So it seems like Apache is hard-coded to treat these requests as being directed to "/" which limits our options somewhat.

Getting your domain added to the HSTS preload list (https://hstspreload.org/) might be useful as well so that (ideally) browsers will automatically switch HTTP to HTTPS even if they haven't yet connected via HTTPS and seen the HSTS header.

3
  • Why downvote? The other answer saying this can't be done without "a lot of additional setup" is objectively wrong. May 9, 2021 at 18:52
  • Fascinating approach, though I'd worry about the genius/madness quotient.
    – TristanK
    Sep 16, 2021 at 7:00
  • may be considered hackish but DOES THE JOB Aug 25, 2022 at 8:25
1

This can be done using the below while also preserving the request URI, in case request URL is different from different users, which is normal when tunneling is needed to reach the web server.

error_page 497 301 =307 https://$http_host$request_uri;

http_host preserves both the host and the port in the URL.

2
  • Where do you put this line? I tried several places in apache2.conf but it gives an error
    – pgr
    Dec 25, 2023 at 18:51
  • This configuration is specific to nginx, not apache Mar 7 at 19:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .