satz
satz

Reputation: 123

Http failure response for (unknown url) - Angular Universal(SSL) on Docker

The error occurs only when api is HTTPS. The testing site is hosted on Digital Ocean.But the below setup is working on my local(MAC Os) with self signed certificate.

Things which i have tried:

Below is my docker compose setup

  1. web - which is nginx container
  2. laravel - which is an api
  3. angualr - Angular universal which consumes api from web
  4. database - mariadb database

docker-compose.yml

version: '3'
services:

  laravel:
    build: ./laravel/docker/php
    depends_on:
      - database
    expose:
      - 9000  
    volumes:
      - ./laravel:/var/www/laravel
      - $HOME/.composer/:$HOME/.composer/
      - ./laravel/docker/php/php-custom.ini:/usr/local/etc/php/conf.d/php-custom.ini


  angular:
    build: ./angular
    expose:
      - 9000
    volumes:
      - ./angular:/var/www/angular:rw
    depends_on:
      - laravel
    links:
      - laravel:laravel

  web:
    build: ./nginx
    volumes:
      - ./:/var/www/
      - ./dh-param/dhparam-2048.pem:/etc/ssl/certs/dhparam-2048.pem:ro
      - /docker-volumes/etc/letsencrypt/live/fabivo.com/fullchain.pem:/etc/letsencrypt/live/fabivo.com/fullchain.pem
      - /docker-volumes/etc/letsencrypt/live/fabivo.com/privkey.pem:/etc/letsencrypt/live/fabivo.com/privkey.pem
    ports:
      - 80:80
      - 443:443
    links:
      - laravel:laravel
      - angular:angular
    depends_on:
      - laravel
      - angular
    environment:
      - VIRTUAL_HOST=fabivo.com, portal.fabivo.com , api.fabivo.com, shop.fabivo.com
    networks:
      default:
        aliases:
          - api.fabivo.com
          - portal.fabivo.com
          - shop.fabivo.com
          - fabivo.com
          - api.paisaclub.com

  database:
    build: ./laravel/docker/mariadb
    environment:
      - "MYSQL_ROOT_PASSWORD=secret"
      - "MYSQL_DATABASE=homestead"
      - "MYSQL_USER=homestead"
      - "MYSQL_PASSWORD=homestead"
    ports:
      - 3306:3306

volumes:
  mysqldata:

networks:
  default:
    external:
      name: nginx-proxy  

nginx config

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name fabivo.com;

    server_tokens off;

    ssl_certificate /etc/letsencrypt/live/fabivo.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/fabivo.com/privkey.pem;

    ssl_buffer_size 8k;

    ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;

    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl_prefer_server_ciphers on;

    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

    ssl_ecdh_curve secp384r1;
    ssl_session_tickets off;

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8;

    location / {
                   # NOTE THERE IS NO TRAILING SLASH AT THE END. NO TRAILING SLASH. NO SLASH. NO!
                    proxy_pass http://angular:9000; # <--- THIS DOES NOT HAVE A TRAILING '/'
                    proxy_set_header X-Real-IP $remote_addr;
                   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header Host $http_host;
                   proxy_http_version 1.1;
                    proxy_set_header X-NginX-Proxy true;
                    proxy_set_header Upgrade $http_upgrade;
                    proxy_set_header Connection "upgrade";
                    proxy_cache_bypass $http_upgrade;
                    proxy_redirect off;
                    proxy_set_header X-Forwarded-Proto $scheme;
                }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name api.fabivo.com portal.fabivo.com shop.fabivo.com;

    server_tokens off;

    ssl_certificate /etc/letsencrypt/live/fabivo.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/fabivo.com/privkey.pem;

    ssl_buffer_size 8k;

    ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;

    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl_prefer_server_ciphers on;

    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

    ssl_ecdh_curve secp384r1;
    ssl_session_tickets off;

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8;

     location / {
                try_files $uri /index.php?$args;
            }

        location ~ \.php$ {
                    fastcgi_split_path_info ^(.+\.php)(/.+)$;
                    fastcgi_pass laravel:9000;
                    fastcgi_index index.php;
                    include fastcgi_params;
                    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                    fastcgi_param PATH_INFO $fastcgi_path_info;
                    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
                    add_header X-XSS-Protection "1; mode=block" always;
                    add_header X-Content-Type-Options "nosniff" always;
                    add_header X-Frame-Options "DENY" always;
                    #CSP
                   # add_header Content-Security-Policy "frame-src 'self'; default-src 'self'; script-src 'self' 'unsafe-inline' https://maxcdn.bootstrapcdn.com https://ajax.googleapis.com; img-src 'self'; style-src 'self' https://maxcdn.bootstrapcdn.com; font-src 'self' data: https://maxcdn.bootstrapcdn.com; form-action 'self'; upgrade-insecure-requests;" always;
                    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
                }
}

server.ts

import 'zone.js/dist/zone-node';
import 'reflect-metadata';
const domino = require('domino');
import { enableProdMode } from '@angular/core';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';
//import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
const app = express();
const compression = require('compression');
const PORT = process.env.PORT || 9000;
const DIST_FOLDER = join(process.cwd(), 'dist');

//
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;

// Our index.html we'll use as our template
const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html'), 'utf8').toString();
const win = domino.createWindow(template);
global['window'] = win;
Object.defineProperty(win.document.body.style, 'transform', {
    value: () => {
        return {
            enumerable: true,
            configurable: true
        };
    },
});
global['document'] = win.document;
global['$'] = require('jquery');
global['jQuery '] = global['$'];
global['Materialize'] = win.Materialize;

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');

const { provideModuleMap } = require('@nguniversal/module-map-ngfactory-loader');

app.engine('html', ngExpressEngine({
    bootstrap: AppServerModuleNgFactory,
    providers: [
        provideModuleMap(LAZY_MODULE_MAP)
    ]
}));


app.use(compression());

app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));

// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), { maxAge: '1y' }));

// All regular routes use the Universal engine
app.get('*', (req, res) => {
    res.render('index', {
        req: req,
        res: res
    });
});

// Start up the Node server
app.listen(PORT, () => {
    console.log(`Node server listening on http://localhost:${PORT}`);
});

UPDATE:

here is minimal reproduction repo https://github.com/ssatz/Angular-SSR-HTTPS-Error Deployed to heroku HEROKU

Note : This is working perfectly in my local with Self Signed certificate.

Upvotes: 1

Views: 1224

Answers (1)

satz
satz

Reputation: 123

This is due to SSL configuration. Incase if any one having the issue, change secp384r1 to prime256v1

ssl_ecdh_curve prime256v1;

Upvotes: 1

Related Questions