sonEtLumiere
sonEtLumiere

Reputation: 4562

nginx reverse proxy Angular Node app mixed content http requests

I'm dealing with nginx and node express server, the app used to works fine with reverse proxy over port 80 but the issue started when i installed a SSL with certbot over nginx, i've been trying also with https node module but i'm still getting mixed content error when i make requests from my angular front to my node backend. I think it's a bad traffic configuration over nginx, maybe i need to set traffic from nginx to node server (port 3000) with http but i'm not sure how to achieve that. Thanks in advance.

Console error when requests:

polyfills-es2015.aa82454585d558e1759e.js:1 Mixed Content: The page at 'https://www.example.com/signup' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://myVpsIpNumber:3000/api/register'. This request has been blocked; the content must be served over HTTPS.

This is my nginx set:

server {

   server_name example.com www.example.com;

    location / {
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {
    if ($host = www.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    server_name example.com www.example.com;
    return 404; # managed by Certbot

}

my express server:

const express = require('express');
const cors = require('cors');

let app = express();

//routes
const user_routes = require('./routes/user.router');

// middlewares
app.use(cors());

app.use(('/'), express.static('client', {redirect: false}));
app.use('/api', user_routes);

app.get('*', function(req, res, next){
    res.sendFile(path.resolve('client/index.html'));
})


// start server
app.listen(3000, () => console.log('Server started at port : 3000'));

Angular service:

import { HttpClient, HttpHeaders } from '@angular/common/http';

noAuthHeader = { headers: new HttpHeaders({ 'NoAuth': 'True' }) };

constructor(private http: HttpClient) {}

  postUser(user: User){
    return this.http.post('http://localhost:3000/api' + '/register', user, this.noAuthHeader);
 }

node backend:

register: (req, res, next) => {
        let user = new User();
        user.email = req.body.email;
        user.password = req.body.password;
    
        user.save((err, doc) => {
            if (!err)
                res.send(doc);
            else {
                if (err.code == 11000)
                    res.status(422).send(['Email ya registrado']);
                else
                    return next(err);
            }
        });
    }

Upvotes: 1

Views: 3589

Answers (3)

Mohsen
Mohsen

Reputation: 1118

If you are using Docker container to host your frontend, make sure that your docker container pulls and uses the latest Docker image with the updated version for apiUrl (e.g., https://example.com/api).

Upvotes: 0

sonEtLumiere
sonEtLumiere

Reputation: 4562

The problem was in API calls from frontend, the solution is replacing the URL with the SSL domain (using https://).

Development:

'http://localhost:3000'

Production:

'https://www.example.com'

import { HttpClient, HttpHeaders } from '@angular/common/http';

noAuthHeader = { headers: new HttpHeaders({ 'NoAuth': 'True' }) };

constructor(private http: HttpClient) {}

postUser(user: User){
  return this.http.post('https://www.example.com/api' + '/register', user, this.noAuthHeader);
}

Upvotes: 2

Funkme2
Funkme2

Reputation: 1

I had the same issue although not with Angular but Vuejs. With http everything worked fine but after installing SSL certificate with certbot I got the "mixed content" error. I'm a beginner and couldn't figure out how to have my frontend talk to backend. It took me quite a while to solve this, so I hope this helps:

  1. Copy your "dist" folder in which you store your production build in this directory /var/www/html like so $ cp -r /usr/src/app/dist/* /var/www/html

  2. Nginx default file at /etc/nginx/sites-available/default should look like this:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        try_files $uri $uri/ =404;
    }
}

server {

    root /var/www/html;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.nginx-debian.html;
    server_name www.example.com example.com; # managed by Certbot


    location / {
        try_files $uri $uri/ =404;
    }


location /api {
         proxy_pass http://localhost:3000; 
         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection 'upgrade';
         proxy_set_header Host $host;
         proxy_cache_bypass $http_upgrade;
        }


    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = www.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80 ;
    listen [::]:80 ;
    server_name www.example.com example.com;
    return 404; # managed by Certbot
}
  1. In frontend use https://example.com/api instead of http://localhost:3000/api like so (not sure if this is working in Angular exactly like this, but you get the point):
postUser(user: User){
    return this.http.post('https://example.com/api' + '/register', user, this.noAuthHeader);
 }
  1. app.js file looks ok. So no changes should be necessary.

Upvotes: 0

Related Questions