简体   繁体   中英

In order to switch my domain to HTTPS, do I need to change Apache or my Node.js app?

I have a web app that runs on my domain. First I had regular HTTP site, which was running on port 8082 on my server, while an Apache server (using virtual hosts) was redirecting requests from port 80 to localhost:8082 .

Now I got an SSL certificate that I tried to install with my site. I made an HTTPS server in Node, and on https://localhost:8082 everything worked as it should.

But then I tried serving my domain over HTTPS. I tried editing my virtual host file to use the certificate, but I think I haven't written it correctly. Also, I tried to make it redirect HTTP to HTTPS, but it didn't work.

What should I do? Should I run an HTTP or HTTPS server in Node, and what should I put in my Apache virtual host configuration?

Here's my virtual host file:

<VirtualHost *:80>
        ServerName www.domain.com
        Redirect permanent / https://www.domain.com
</VirtualHost>

<VirtualHost *:443>

        ServerName domain.com
        ServerAlias www.domain.com

        SSLEngine On
        SSLProxyEngine On
        SSLCertificateFile "/home/USERNAME/Projects/NODEAPP/chained.pem"
        SSLCertificateKeyFile "/home/USERNAME/Projects/NODEAPP/domain.key"

        ProxyPreserveHost On
        ProxyRequests off

        <Proxy *>
                Order deny,allow
                Allow from all
        </Proxy>

        <Location />
                ProxyPass http://localhost:8082/

                ProxyPassReverse http://localhost:8082/
        </Location>

</VirtualHost>

(Fair warning: my understanding of your question is that you want https://www.domain.com to appear in the browser's URL bar, not https://www.domain.com:8082 . If that's not the case a lot of the below is wrong, but will probably still help you understand your problem better.)

Background

(aka, HTTP design crash course because I think you don't quite understand what's going on, but feel free to skip if you do:)

I think you have a misconception as to what Apache's doing - mostly because you're saying that it's "redirecting" requests.

An HTTP redirect is any(?) response with a status code in the 3xx range, and it tells your browser that the resource it's requested has moved somewhere else. For example, let's say that http://example.com/foo used to exist, but has since been moved to http://example.org/bar (note the .com and .org difference). If you type in http://example.com/foo into your URL bar, your browser will request /foo (specifically it will send an HTTP GET request) to example.com . example.com will then send an HTTP response back to the browser redirecting it to http://example.org/bar . Then the browser will send an HTTP GET request for /bar to example.org and get back a response containing the resource.

Here's a diagram:

Step 1:

-------------                                   --------------------------
|           |                                   |                        |
|  Browser  | -------- HTTP GET /foo ---------> | example.com web server |
|           | <-- HTTP 301 Moved Permanently -- |                        |
-------------                                   --------------------------

Step 2:

-------------                        --------------------------
|           |                        |                        |
|  Browser  | --- HTTP GET /bar ---> | example.org web server |
|           | <---- HTTP 200 OK ---- |                        |
-------------                        --------------------------

Now, here's the thing. That's not what you're doing, nor probably what you want to be doing. What you're doing is called reverse proxying, which is where whenever the web server (in your case Apache) receives a request, it just forwards it somewhere else. In your original (all-HTTP) setup, the web browser would request www.domain.com from Apache, then Apache would simply forward that request, with little to no modification, to http://localhost:8082 . Here's the diagram:

Step 1:

-------------                        ----------                        ------------------
|           |                        |        |                        |                |
|           | ----- HTTP GET / ----> |        |                        |                |
|  Browser  |                        | Apache | ----- HTTP GET / ----> | localhost:8082 |
|           |                        |        | <---- HTTP 200 OK ---- |                |
|           | <---- HTTP 200 OK ---- |        |                        |                |
-------------                        ----------                        ------------------

Step 2:

There is no step 2. BOOM.

The really important thing to note here is that the browser doesn't "see" Node.js, it sees Apache on the other end. Likewise Node.js doesn't "see" the browser, it sees Apache (although typically Apache will augment the request with details about the browser connection - see for example the X-Forwarded-For header).

This is an intentional part of the design of HTTP - HTTP request and response semantics don't imply anything about the internal implementation details of how requests are processed. That's why HTTP is so powerful. It lets you create really complex setups - think what you're doing but on a much bigger scale and with even more components - and then abstract over that complication with a simple, uniform interface that's shown to the external world: your URL hierarchy combined with the HTTP request/response cycle.

How to solve your actual problem

Now that we've established what you're trying to do, here's what your problem is: you're conflating what protocol Node.js is speaking with what protocol Apache is speaking (and thus what the external world is seeing).

Your end goal is for people to connect to your website over HTTPS, right? In that case, you don't need Node.js to speak HTTPS, because the only thing that directly talks to Node.js is Apache. Apache is the thing that speaks to browsers, so Apache is what you need to use HTTPS. Ideally, you'd have Apache speak HTTPS to browsers and HTTP to Node.js - it doesn't matter if Apache encrypts traffic to Node because Node is on localhost. In diagram form:

-------------                         ----------                        ------------------
|           |                         |        |                        |                |
|           | ----- HTTPS GET / ----> |        |                        |                |
|  Browser  |                         | Apache | ----- HTTP GET / ----> | localhost:8082 |
|           |                         |        | <---- HTTP 200 OK ---- |                |
|           | <---- HTTPS 200 OK ---- |        |                        |                |
-------------                         ----------                        ------------------

So make your Node app listen for HTTP requests, then fix your Apache config to serve stuff with HTTPS, but speak HTTP to the Node backend.

I think what's wrong with your configuration is that you need quotes around the path, ie <Location "/"> . Alternately in the reverse proxy configs that I have, I have ProxyPass directives set up without a <Location> block, like so:

ProxyPass / http://localhost:8082/
ProxyPassReverse / http://localhost:8082/

so you could try that too.

If it still doesn't work, try removing the <Proxy> / </Proxy> block - I'm not really sure what that does, but I don't have anything like that in my reverse proxy configurations (which work) - so it might be interfering with something.

As for your HTTP to HTTPS redirect, I don't really see anything wrong with it. Are you sure you're connecting to www.domain.com instead of domain.com ? The second VirtualHost serves both, but the first serves only the former.

From your description I'm going to summarize your problem as follows:

  1. You've configured node.js to accept TLS connections

  2. You want Apache to accept TLS connections

OK. So first question. You said:

I made https server in Node, and on https://localhost:8082 everything worked as it should.

Without changing anything, what happens when you try to access http://localhost:8082 ? I can tell you what happens (no guesses, no "should", I can definitely tell you) but you should at least try it in order to see for yourself what happens.

SPOILERS: HTTP does not support listening for both TLS and unencrypted connections on a single port. It's just the way the protocol was specified. Other protocols like POP3, SMTP, FTP etc have the capability to do this but not HTTP. So what happens is trying to access http://localhost:8082 will fail.

Now, look carefully at your Apache config:

# THIS is the problematic part:
ProxyPass         http://localhost:8082/
ProxyPassReverse  http://localhost:8082/
#                   ^
#                   |______ notice this?

So the problem is you are proxying to a url that does not work.

You have two options here. Both of them valid depending on how you want to design your architecture.

  1. Proxy to https instead of http .

     ProxyPass https://localhost:8082/ ProxyPassReverse https://localhost:8082/ 

    The advantage of this is that you get end-to-end encryption. Even if someone manage to login to your server they can't listen in to the connection. The disadvantage of this is you're encrypting twice which mean you're using much more CPU time to serve a request.

  2. Remove TLS from node.js.

    The advantage of this is that you're letting Apache handle all encryption so your web app does not need to spend any CPU time handling encryption itself. For very large services like Google or Facebook they can even offload the encryption to another front-end server (or more likely servers) so that the server running your web app won't be busy encrypting and decrypting HTTP connections. The disadvantage is that anyone who can login to your server can easily listen in to the connection.

There is a third way that some people do but it's getting less and less popular. Run node.js listening on two ports. For example, configure one to listen to 8082 for http and also listen to 8084 for https then you can proxy http pages to 8082 and https pages to 8084. However, looking at your Apache config I can tell this is not what you want to do.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM