Aller au contenu principal

Docker et nginx multi-projets

Peut-être avez-vous plusieurs projets à déployer. Si c'est le cas, il vous faudra modifier la configuration de nginx, docker-compose.yml, en plus de créer un Dockerfile additionnel.

De plus, il vous faudra un domaine additionnel. Je vous suggère d'utiliser un sous-domaine pour simplifier le tout. Par exemple, assumons que vous avez déjà déployé un site sous mondomaine.com et que vous vouliez déployer une API. Utilisez api.mondomaine.com pour déployer l'API.

Créer un sous-domaine

Chez votre registrar (là où vous avez enregistré votre nom de domaine), créez une nouvelle entrée DNS qui pointe vers votre serveur. Créez cette entrée avec le type A Record.

img

Configurer le projet

  1. Créer un fichier Dockerfile dans le nouveau projet et mettre les instructions de compilation. Le fichier devrait être très près de ce que vous avez déjà.
    Snowfall.Web.Api/Dockerfile
    # Use the ASP.NET runtime as base
    FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
    WORKDIR /app
    EXPOSE 80
    EXPOSE 443

    # Build the app
    FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
    WORKDIR /src
    COPY ["Snowfall.Web.Api/Snowfall.Web.Api.csproj", "Snowfall.Web.Api/"]
    RUN dotnet restore "Snowfall.Web.Api/Snowfall.Web.Api.csproj"
    COPY . .
    RUN dotnet publish "Snowfall.Web.Api/Snowfall.Web.Api.csproj" -c Release -o /app/publish

    FROM base AS final
    WORKDIR /app
    COPY --from=build /app/publish .
    ENTRYPOINT ["dotnet", "Snowfall.Web.Api.dll"]
  2. Modifiez le fichier docker-compose.yml pour ajouter le nouveau service.
    services:
    postgres:
    image: postgres:17-alpine
    container_name: snowfall_postgres
    environment:
    - POSTGRES_DB=${POSTGRES_DB}
    - POSTGRES_USER=${POSTGRES_USER}
    - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
    - pgdata:/var/lib/postgresql/data

    client:
    build:
    context: .
    dockerfile: Snowfall.Web.Mvc/Dockerfile
    container_name: snowfall_client
    environment:
    - ASPNETCORE_URLS=${ASPNETCORE_URLS}
    - DossierStorage=${DossierStorage}
    - ConnectionStrings__AppDatabaseConnection=${APP_DATABASE_CONNECTION}
    expose:
    - "80"
    volumes:
    - shared-images:/storage-images
    depends_on:
    - postgres

    api:
    build:
    context: .
    dockerfile: Snowfall.Web.Api/Dockerfile # Chemin vers le Dockerfile de l'API
    container_name: snowfall_api
    environment:
    - ASPNETCORE_URLS=http://+:5000 # Port interne pour l'API
    - DossierStorage=${DossierStorage}
    - ConnectionStrings__AppDatabaseConnection=${APP_DATABASE_CONNECTION}
    expose:
    - "5000" # Expose le port interne
    volumes:
    - shared-images:/storage-images
    depends_on:
    - postgres

    reverse-proxy:
    image: nginx:alpine
    container_name: reverse_proxy
    ports:
    - "80:80"
    - "443:443"
    volumes:
    - ./nginx.conf:/etc/nginx/nginx.conf:ro
    - certs:/etc/letsencrypt
    - certs-data:/data/letsencrypt
    depends_on:
    - client
    - api # Ajouter l'API comme dépendance

    certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
    - certs:/etc/letsencrypt
    - certs-data:/data/letsencrypt

    volumes:
    pgdata:
    shared-images:
    certs:
    certs-data:
  3. Modifiez nginx.conf pour ajouter le nouveau service
    nginx.conf
    events { }

    http {
    upstream client_app {
    server client:80;
    }

    upstream api_app {
    server api:5000;
    }

    # Bloc pour les requêtes HTTP
    server {
    listen 80;
    server_name snowfallweb.com www.snowfallweb.com api.snowfallweb.com;

    # Pour Certbot
    location /.well-known/acme-challenge/ {
    root /data/letsencrypt;
    }

    # Redirige le reste des requêtes vers HTTPS
    location / {
    return 301 https://$host$request_uri;
    }
    }

    # Bloc pour les requêtes HTTPS
    server {
    listen 443 ssl;
    server_name snowfallweb.com www.snowfallweb.com;

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

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Permet également le challenge pour HTTPS
    location /.well-known/acme-challenge/ {
    root /data/letsencrypt;
    }

    location / {
    proxy_pass http://client_app;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    }

    # Bloc pour les requêtes HTTPS pour l'API
    server {
    listen 443 ssl;
    server_name api.snowfallweb.com;

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

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Permet également le challenge pour HTTPS
    location /.well-known/acme-challenge/ {
    root /data/letsencrypt;
    }

    location / {
    proxy_pass http://api_app;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    }
    }
    }

Construire la nouvelle image

  1. git pull les derniers changements
  2. docker compose stop pour arrêter le conteneur
  3. docker compose build api pour seulement construire la nouvelle image.

Demander un certificat

Nous avons un enjeu! Pour demander un certificat, il faut partir le conteneur, mais le conteneur (nginx) s'attend à un fichier de certificat SSL. Bref, le serveur ne pourra pas partir et donc on ne pourra pas demander de certificat.

Nous allons ainsi suivre les étapes suivantes:

  1. Modifier temporairement le fichier nginx.conf pour exclure le sous-domaine.
  2. Redémarrer Nginx pour qu’il ne tente plus de charger le certificat manquant.
  3. Utiliser Certbot pour générer le certificat SSL.
  4. Réintégrer le bloc serveur pour le sous-domaine API dans nginx.conf.
  5. Redémarrer Nginx pour appliquer les changements.

**Vous pouvez faire toutes ces modifs directement sur le serveur.

  1. Ouvrez le fichier nginx.conf
    nano nginx.conf
  2. Mettez en commentaire toute la portion "serveur" en lien avec le nouveau projet/domaine
    # server {
    # listen 443 ssl;
    # server_name api.snowfallweb.com;

    # ssl_certificate /etc/letsencrypt/live/api.snowfallweb.com/fullchain.pem;
    # ssl_certificate_key /etc/letsencrypt/live/api.snowfallweb.com/privkey.pem;

    # ssl_protocols TLSv1.2 TLSv1.3;
    # ssl_ciphers HIGH:!aNULL:!MD5;
    # ssl_prefer_server_ciphers on;

    # location /.well-known/acme-challenge/ {
    # root /data/letsencrypt;
    # }

    # location / {
    # proxy_pass http://api_app;
    # proxy_set_header Host $host;
    # proxy_set_header X-Real-IP $remote_addr;
    # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # proxy_set_header X-Forwarded-Proto $scheme;
    # }
    # }
  3. Enregistrez le fichier (CTRL+X et ensuite, Y)
  4. Démarrez le conteneur
    docker compose up -d
  5. Demandez un certificat pour le sous-domaine
    docker compose run certbot certonly --webroot --webroot-path=/data/letsencrypt -d api.snowfallweb.com
  6. Confirmez que le certificat a été généré
    Successfully received certificate.
    Certificate is saved at: /etc/letsencrypt/live/api.snowfallweb.com/fullchain.pem
    Key is saved at: /etc/letsencrypt/live/api.snowfallweb.com/privkey.pem
    This certificate expires on 2025-04-27.
    These files will be updated when the certificate renews.
  7. Réactivez la zone "Server" qui a été mise en commentaire précédemment
  8. Repartez le service nginx
    docker compose restart reverse-proxy