Introduction

On nous demande souvent comment héberger nos applications front-end et plus particulièrement nos applications Angular. Dans la plupart des cas c’est très simple, les webApps Angular étant des applications statiques, elles sont servies par un serveur Apache ou Nginx avec un système de redirection qui renvoie toutes les routes vers le fichier index.html.

Mais parfois nous avons besoin de servir plusieurs webApps sur le même domaine. On a alors la possibilité d’utiliser des sous-domaines pour séparer nos applications app1.mondomaine.com et app2.mondomaine.com et configurer le serveur web pour servir les deux applications en fonction du nom de domaine (configuration des VirtualHosts).

Mais dans le cas où l’on ne veut pas utiliser de sous-domaines et héberger nos deux applications sur le même domaine, la mise en place devient moins évidente. Dans cet article, nous allons étudier la mise en place d’un serveur web répondant à un seul nom de domaine et qui servira deux applications web. Nous allons pour cela créer deux applications Angular, et les héberger sur le même serveur Nginx l’une à l’adresse http://www.mondomaine.com/ et la seconde sur http://www.mondomaine.com/appTwo/

Créer les différentes applications Angular, appOne, appTwo.

Application appOne

Dans un premier temps, nous allons créer notre première application Angular via le CLI et la commande ng new appOne et on va ensuite activer le routeur et le choix des styles SCSS.

Notre application Angular appOne est créée. Il nous reste à créer deux routes sur cette application de test.

On crée deux composants nommés routeOne et routeTwo via la commande du CLI

ng generate component components/routeOne
ng generate component components/routeTwo

Une fois ces deux routes créées, nous allons ajouter un peu de style, juste pour habiller notre application. Pour cela, nous allons utiliser Bootstrap.

yarn add bootstrap

Puis dans le ficher de configuration angular.json ajouter les styles de bootstrap :

...
  "styles": [
    "node_modules/bootstrap/dist/css/bootstrap.min.css",
    "src/styles.scss"
  ],
...

Nous allons ensuite importer les styles bootstrap dans le fichier styles.scss :

@import "~bootstrap/dist/css/bootstrap.min.css";
/* You can add global styles to this file, and also import other style files */

.container {
  margin-top: 20px;
}

.jumbotron {
  background-color: #e9ecef;

  &.color {
    background-color: #cccccc;
  }
}

Et enfin, nous allons modifier notre application avec les snippets de code disponible sur ce gist

Après avoir exécuté la commande ng serve --open , vous devriez obtenir cette application :

Application appTwo

On recommence la même manipulation pour créer notre seconde application.

On génère l’application avec la commande ng new appTwo.

On installe bootstrap via yarn add bootstrap et on modifie le fichier angular.json et styles.scss.

On crée à nouveau deux composants routeOne et routeTwo.

Et pour finir nous allons modifier le design de notre seconde application disponible via ce gist. Le thème est légèrement modifié afin de bien les différencier. 

On doit obtenir la seconde application :

Les deux applications diffèrent par le thème de leur appBar. (clair pour appOne et foncé pour appTwo).

Maintenant, nous allons packager les deux applications via les commandes suivantes :

  • Pour appOne qui sera servie sur http://www.mondomaine.com/
ng build --prod
  • Pour appTwo qui sera servie sur http://www.mondomaine.com/admin
ng build --prod --base-href=/admin/

Voilà, nos deux applications sont packagées dans le répertoire dist de leurs dossiers respectifs.

Utiliser Docker pour avoir un serveur Nginx

Afin d’éviter d’avoir à installer un serveur Nginx sur sa machine, nous allons utiliser docker et créer une image contenant à la fois un serveur Nginx et nos deux applications.

Dans un premier temps, créer un dossier server, puis dans ce dossier créer deux sous-dossiers appOne et appTwo. Dans chacun des dossiers, copier les fichiers des applications packagées présents dans les dossiers appOne/dist/appOne et appTwo/dist/appTwo.

Nous allons maintenant créer le fichier Dockerfile à la racine du dossier server afin de créer notre image Docker.

FROM nginx:stable-alpine

WORKDIR /usr/share/nginx/html

COPY appOne/dist/appOne /usr/share/nginx/html/appOne
COPY appTwo/dist/appTwo /usr/share/nginx/html/appTwo

EXPOSE 80

On crée notre image à partir de l’image : FROM nginx:stable-alpine.

On définit le répertoire de travail : WORKDIR /usr/share/nginx/html.

On copie les deux applications appOne et appTwo :
COPY appOne/dist/appOne /usr/share/nginx/html/appOne
COPY appTwo/dist/appTwo /usr/share/nginx/html/appTwo

Enfin on expose le port 80 du conteneur : EXPOSE 80

On a maintenant une première version de notre image Docker, nous reviendrons dessus une fois la configuration Nginx terminée.

Configurer Nginx

Créer un fichier ngx.conf dans le répertoire server. Ce fichier va nous permettre de créer notre configuration du serveur Nginx afin de servir nos deux applications.

Le fichier va contenir un bloc server qui va écouter sur le port 8080 et qui aura pour nom localhost.

server {
  listen 8080;
  server_name localhost;
}

Au sein du bloc server, nous allons ajouter un premier bloc location qui va permettre de configurer la première redirection vers l’application servie sur le ‘/‘, dans notre cas appOne:

server {
  listen 8080;
  server_name localhost;

  location / {
    root /usr/share/nginx/html/appOne;
    try_files $uri $uri/ /index.html;
  }

}

Pour charger cette configuration, nous allons revenir sur notre fichier Dockerfile pour ajouter la configuration Nginx.

FROM nginx:stable-alpine

WORKDIR /usr/share/nginx/html

COPY appOne/dist/appOne /usr/share/nginx/html/appOne
COPY appTwo/dist/appTwo /usr/share/nginx/html/appTwo

COPY ngx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

A ce stade, nous servons une seule de nos deux applications. Si on build notre image Docker et qu’on lance cette image, nous obtenons l’application appOne servie sur le ‘/’. 

Vérifions avec les commandes suivantes à exécuter dans le dossier server :

On crée notre image Docker à partir de notre Dockerfile

docker build -t nginx-ngx .

On exécute notre image Docker

docker run --name ngx-nginx -d -p 8080:8080 nginx-ngx

On peut maintenant ouvrir notre navigateur à l’url suivante http://localhost:8080 pour obtenir :

On navigue bien d’une page à une autre mais lors du clic sur le bouton Admin, on est redirigé sur la home ce qui est normal puisque aucune application n’est présente sur la route ‘/admin’.

Configuration de l’application appTwo

Nous allons ajouter un nouveau bloc location au dessus du premier bloc location :

server {
  listen 8080;
  server_name localhost;

  location /admin {
    root /usr/share/nginx/html/appTwo;
    try_files $uri $uri/ admin/index.html;
  }

  location / {
    root /usr/share/nginx/html/appOne;
    try_files $uri $uri/ /index.html;
  }

}

De cette manière nous devrions obtenir nos deux applications, appOne étant servie sur le ‘/’ et appTwo sur le ‘/admin’. Vérifions ça de suite en re-créant l’image Docker puis en l’exécutant.

On se rend compte que l’application appOne fonctionne bien, son router également mais que l’application appTwo ne fonctionne pas sur l’url ‘/admin’.

Dans le bloc location /Admin, on peut changer root par alias, ça ne change rien.

La solution passe par une redirection avec une regex. Dans le bloc location /admin, nous allons ajouter une redirection permanente utilisant une Regex:

server {
  listen 80;
  server_name localhost;

  location /admin {
    alias /usr/share/nginx/html/appTwo;
    rewrite ^(.*)\/\/([a-zA-Z0-9-.:]*)\/?(.*)$ $2/$3 permanent;
    try_files $uri $uri/ /admin/index.html;
  }

  location / {
    root /usr/share/nginx/html/appOne;
    try_files $uri $uri/ /index.html;
  }

}

Voici comment la regex découpe l’url en 3 blocs qui va nous permettre d’effectuer une redirection des blocs 2 et 3 de façon permanente :

 

Pour vérifier si cela fonctionne, il nous reste à re-créer l’image Docker et à l’exécuter.

docker rmi nginx-ngx

Puis

docker build -t nginx-ngx .

Et enfin

docker run --name ngx-nginx -d -p 8080:80 nginx-ngx

 

ET voilà le site fonctionne comme on le souhaite.