diff --git a/CHANGELOG.md b/CHANGELOG.md index e15e622..7c51ea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ Format inspiré de [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/). +## [1.0.1] — 2026-09-12 + +### Corrigé +- **L'interface ne démarrait pas.** nginx 1.27.5 a déplacé son fichier PID de + `/var/run/nginx.pid` vers `/run/nginx.pid` ; le `sed` du Dockerfile visait + l'ancien chemin, ne correspondait plus à rien, et nginx échouait sur + « open() "/run/nginx.pid" failed (13: Permission denied) ». L'image de base + devient `nginxinc/nginx-unprivileged`, conçue pour l'exécution non + privilégiée — plus aucune retouche par `sed`. +- Sonde de santé de l'interface basée sur `wget` (présent dans busybox) plutôt + que `curl`, qui n'est pas dans l'image Alpine. +- `POSTGRES_PASSWORD` : consigne de génération corrigée en hexadécimal. Le + base64 produit des caractères `/` et `+` qui rendent l'URL de connexion + invalide et empêchent l'API de démarrer. + ## [1.0.0] — 2026-09-12 Première version. diff --git a/VERSION b/VERSION index 3eefcb9..7dea76e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.0.1 diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 3cbd3e1..be3e9a8 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "limier" -version = "1.0.0" +version = "1.0.1" description = "Plateforme OSINT auto-hébergée : pseudonyme, nom, e-mail, domaine" requires-python = ">=3.12,<3.14" license = { text = "MIT" } diff --git a/backend/src/limier/__init__.py b/backend/src/limier/__init__.py index 237f114..5a4ca3a 100644 --- a/backend/src/limier/__init__.py +++ b/backend/src/limier/__init__.py @@ -1,3 +1,3 @@ """Limier — plateforme OSINT auto-hébergée.""" -__version__ = "1.0.0" +__version__ = "1.0.1" diff --git a/deploy/.env.example b/deploy/.env.example index 0dd8991..72ce316 100644 --- a/deploy/.env.example +++ b/deploy/.env.example @@ -7,14 +7,19 @@ # --------------------------------------------------------------------------- REGISTRY=registry.tips-of-mine.com -TAG=1.0.0 +TAG=1.0.1 LIMIER_HOST=limier.tips-of-mine.com LIMIER_PUBLIC_URL=https://limier.tips-of-mine.com LIMIER_ENVIRONMENT=prod LIMIER_LOG_LEVEL=INFO # --- Base de données ------------------------------------------------------- -# Vault. Générer : openssl rand -base64 32 +# Vault. Générer : openssl rand -hex 24 +# +# Hexadécimal et non base64 : ce mot de passe est injecté tel quel dans l'URL +# de connexion (postgresql+asyncpg://limier:MOT_DE_PASSE@...). Les caractères +# « / » et « + » produits par base64 rendent cette URL invalide et l'API refuse +# de démarrer. POSTGRES_PASSWORD= # --- Authentification Authentik -------------------------------------------- diff --git a/deploy/essai/LISEZMOI.md b/deploy/essai/LISEZMOI.md new file mode 100644 index 0000000..b4fc455 --- /dev/null +++ b/deploy/essai/LISEZMOI.md @@ -0,0 +1,135 @@ +# Essayer Limier sur SLDOKP03, sans engager la production + +Deux niveaux, du plus léger au plus complet. + +--- + +## Niveau 1 — un moteur, une commande, aucune configuration + +Ni base de données, ni Redis, ni Authentik. On appelle le moteur directement. + +```bash +cd /opt # ou n'importe où, il suffit d'avoir essai_moteur.py sous la main + +docker run --rm -v "$PWD/essai_moteur.py:/tmp/essai.py" \ + registry.tips-of-mine.com/limier/limier-backend:1.0.1 \ + python /tmp/essai.py domain tips-of-mine.com +``` + +Le moteur domaine répond en quelques secondes : RDAP, DNS complet, posture de +messagerie, puis les sous-domaines issus des journaux de certificats. + +Le moteur pseudonyme, en version courte : + +```bash +docker run --rm -v "$PWD/essai_moteur.py:/tmp/essai.py" \ + -e LIMIER_USERNAME_TOP_SITES=80 \ + registry.tips-of-mine.com/limier/limier-backend:1.0.1 \ + python /tmp/essai.py username soxoj +``` + +Et la recherche par nom, qui montre les variantes déduites : + +```bash +docker run --rm -v "$PWD/essai_moteur.py:/tmp/essai.py" \ + -e LIMIER_USERNAME_TOP_SITES=60 \ + registry.tips-of-mine.com/limier/limier-backend:1.0.1 \ + python /tmp/essai.py name "Hubert Cornet" +``` + +**Ce qu'il faut regarder** : le taux de sites non vérifiés. C'est la mesure +directe de ce que vaut ta sortie réseau actuelle, et c'est l'information qui +décide du chantier proxies. + +--- + +## Niveau 2 — l'interface complète, en local + +Cinq conteneurs, un seul port, aucun lien avec Traefik ni le tunnel Cloudflare. + +### 1. Authentik + +L'interface ne sert à rien sans connexion : chercher exige un compte. Crée un +fournisseur **distinct** de celui de production, pour ne pas polluer ce dernier +avec une URI de redirection en HTTP. + +Applications → Fournisseurs → Créer → OAuth2/OpenID : + +| Champ | Valeur | +| --- | --- | +| Nom | `Tips-Of-Mine-Limier-Essai` | +| Type de client | Confidentiel | +| Flux d'autorisation | `default-provider-authorization-implicit-consent` | +| **URIs de redirection** | `http://10.0.4.50:8088/api/auth/retour` | + +Remplace l'IP par celle de SLDOKP03. Authentik acceptera l'URL en HTTP. + +Applications → Applications → Créer, nom `Limier (essai)`, **slug +`limier-essai`**, fournisseur ci-dessus. Lie ton groupe `GL-Limier-Admin`. + +Relève l'identifiant et le secret du client. + +### 2. Configuration + +```bash +mkdir -p /opt/limier-essai && cd /opt/limier-essai +# y déposer docker-compose.essai.yml, nginx-essai.conf et .env.essai +cp .env.essai .env +``` + +Renseigne dans `.env` : `ESSAI_URL` (la même URL que l'URI de redirection, sans +le chemin), `LIMIER_OIDC_CLIENT_ID` et `LIMIER_OIDC_CLIENT_SECRET`. + +### 3. Démarrage + +```bash +docker compose -f docker-compose.essai.yml run --rm essai-api alembic upgrade head +docker compose -f docker-compose.essai.yml up -d +docker compose -f docker-compose.essai.yml ps +``` + +Puis ouvre `http://10.0.4.50:8088`. + +### 4. Ce qu'il y a à voir + +- **Se connecter** : redirection Authentik, retour sur l'interface, ton nom et + ton plan apparaissent en haut à droite. +- **Recherche par nom** : tape « Hubert Cornet ». Les variantes déduites + s'affichent **avant** le lancement — c'est le comportement demandé, une + identité et non des mots séparés. +- **Progression en direct** : les résultats arrivent au fil de l'eau. Si tout + apparaît d'un coup à la fin, c'est que le flux SSE est mis en tampon quelque + part. +- **Filtre de confiance** : bascule entre « Tous », « Probables et + » et + « Confirmés » pour juger de la pertinence du barème. +- **Les signaux** sous chaque résultat : c'est ce qui explique le classement. +- **Recherche par domaine** sur `tips-of-mine.com` : tu devrais retrouver tes + propres sous-domaines via les journaux de certificats. + +### 5. Tout effacer + +```bash +docker compose -f docker-compose.essai.yml down -v +``` + +Le `-v` supprime aussi les volumes : il ne reste rien, ni base, ni recherche. + +--- + +## Réglages d'essai à connaître + +La pile d'essai n'est **pas** la configuration de production : + +| Réglage | Essai | Production | Pourquoi | +| --- | --- | --- | --- | +| `LIMIER_ENVIRONMENT` | `dev` | `prod` | cookies non « Secure », obligatoire en HTTP | +| `LIMIER_USERNAME_TOP_SITES` | 120 | 500 | recherches de 20 s au lieu de 2 min | +| `LIMIER_WORKER_MAX_JOBS` | 1 | 4 | SLDOKP03 fait déjà tourner beaucoup | +| `LIMIER_STORE_RAW_IDENTIFIERS` | `true` | `false` | voir les termes en clair dans l'historique | +| Secrets | en clair | Vault | ce sont des secrets d'essai, à ne pas réutiliser | + +## Charge + +Cinq conteneurs, dont un PostgreSQL et un Redis plafonné à 128 Mio. Le worker +est le poste le plus gourmand : à `LIMIER_WORKER_MAX_JOBS=1` et 30 connexions +simultanées, il reste modeste. L'essai se démonte entièrement avec `down -v`. diff --git a/deploy/essai/docker-compose.essai.yml b/deploy/essai/docker-compose.essai.yml new file mode 100644 index 0000000..3eed41a --- /dev/null +++ b/deploy/essai/docker-compose.essai.yml @@ -0,0 +1,110 @@ +# Pile d'essai — NE PAS UTILISER EN PRODUCTION. +# +# Différences volontaires avec deploy/docker-compose.yml : +# - aucun réseau Traefik, aucune étiquette, aucun tunnel Cloudflare ; +# - tout est exposé sur un seul port local (8088) ; +# - nginx relaie /api vers l'API, pour que l'interface et l'API partagent la +# même origine — sans quoi le cookie de session ne serait pas transmis ; +# - LIMIER_ENVIRONMENT=dev : cookies non « Secure » (indispensable en HTTP) +# et contrôle de complétude de la configuration désactivé ; +# - données en volumes nommés, supprimables d'un coup en fin d'essai. +# +# Démarrage : docker compose -f docker-compose.essai.yml up -d +# Arrêt total : docker compose -f docker-compose.essai.yml down -v + +name: limier-essai + +x-env: &env + LIMIER_ENVIRONMENT: dev + LIMIER_LOG_LEVEL: INFO + LIMIER_LOG_FORMAT: console + LIMIER_PUBLIC_URL: ${ESSAI_URL:?renseigner ESSAI_URL dans .env} + LIMIER_DATABASE_URL: postgresql+asyncpg://limier:essai@essai-postgres:5432/limier + LIMIER_REDIS_URL: redis://essai-redis:6379/0 + LIMIER_OIDC_ISSUER: ${LIMIER_OIDC_ISSUER} + LIMIER_OIDC_CLIENT_ID: ${LIMIER_OIDC_CLIENT_ID} + LIMIER_OIDC_CLIENT_SECRET: ${LIMIER_OIDC_CLIENT_SECRET} + LIMIER_OIDC_ADMIN_GROUP: GL-Limier-Admin + LIMIER_OIDC_INTERNAL_GROUP: GL-Limier + LIMIER_SESSION_SECRET: secret-d-essai-uniquement-a-ne-pas-reutiliser-ailleurs + LIMIER_IDENTIFIER_HASH_PEPPER: poivre-d-essai + LIMIER_STORE_RAW_IDENTIFIERS: "true" + # Profondeur réduite : 120 sites au lieu de 500, pour des recherches de + # 20 à 30 secondes plutôt que deux minutes. + LIMIER_USERNAME_TOP_SITES: "120" + LIMIER_USERNAME_MAX_CONNECTIONS: "30" + # Un seul travail à la fois : SLDOKP03 fait déjà tourner beaucoup de choses. + LIMIER_WORKER_MAX_JOBS: "1" + LIMIER_DNS_RESOLVERS: 1.1.1.1,9.9.9.9 + TZ: Europe/Paris + +services: + + essai-api: + image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-backend:${TAG:-1.0.0} + container_name: essai-limier-api + restart: "no" + command: ["limier-api"] + environment: *env + volumes: + - essai-sites:/data/sites + depends_on: + essai-postgres: { condition: service_healthy } + essai-redis: { condition: service_healthy } + + essai-worker: + image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-backend:${TAG:-1.0.0} + container_name: essai-limier-worker + restart: "no" + command: ["limier-worker"] + environment: *env + volumes: + - essai-sites:/data/sites + depends_on: + essai-postgres: { condition: service_healthy } + essai-redis: { condition: service_healthy } + + essai-web: + image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-frontend:${TAG:-1.0.0} + container_name: essai-limier-web + restart: "no" + ports: + - "${ESSAI_PORT:-8088}:8080" + volumes: + # Remplace la configuration nginx livrée : celle de production ne relaie + # pas /api, ce rôle étant tenu par Traefik. + - ./nginx-essai.conf:/etc/nginx/conf.d/default.conf:ro + depends_on: + - essai-api + + essai-postgres: + image: postgres:16.10-alpine + container_name: essai-limier-postgres + restart: "no" + environment: + POSTGRES_USER: limier + POSTGRES_PASSWORD: essai + POSTGRES_DB: limier + TZ: Europe/Paris + volumes: + - essai-postgres:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U limier -d limier"] + interval: 5s + timeout: 3s + retries: 10 + + essai-redis: + image: redis:7.4-alpine + container_name: essai-limier-redis + restart: "no" + command: ["redis-server", "--save", "", "--appendonly", "no", "--maxmemory", "128mb"] + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 10 + +volumes: + essai-postgres: + essai-sites: diff --git a/deploy/essai/essai_moteur.py b/deploy/essai/essai_moteur.py new file mode 100644 index 0000000..a067b33 --- /dev/null +++ b/deploy/essai/essai_moteur.py @@ -0,0 +1,142 @@ +"""Essai d'un moteur, hors de toute infrastructure. + +Ni PostgreSQL, ni Redis, ni Authentik : on instancie le moteur, on consomme son +flux d'évènements et on affiche ce qui sort. C'est exactement ce que fait le +worker, moins la persistance. + +Utilisation, depuis l'image publiée : + + docker run --rm -v "$PWD/essai_moteur.py:/tmp/essai.py" \ + registry.tips-of-mine.com/limier/limier-backend:1.0.0 \ + python /tmp/essai.py domain tips-of-mine.com + + docker run --rm -v "$PWD/essai_moteur.py:/tmp/essai.py" \ + -e LIMIER_USERNAME_TOP_SITES=80 \ + registry.tips-of-mine.com/limier/limier-backend:1.0.0 \ + python /tmp/essai.py username soxoj + + docker run --rm -v "$PWD/essai_moteur.py:/tmp/essai.py" \ + registry.tips-of-mine.com/limier/limier-backend:1.0.0 \ + python /tmp/essai.py name "Hubert Cornet" + +Le type ``username`` sur 500 sites prend une à deux minutes. Pour un premier +aperçu, ``LIMIER_USERNAME_TOP_SITES=80`` ramène cela à une vingtaine de +secondes et suffit largement à juger du rendu. +""" + +from __future__ import annotations + +import asyncio +import os +import sys +import time + +os.environ.setdefault("LIMIER_ENVIRONMENT", "dev") +os.environ.setdefault("LIMIER_LOG_FORMAT", "console") +os.environ.setdefault("LIMIER_LOG_LEVEL", "WARNING") + +from limier.db.models import SearchKind # noqa: E402 +from limier.engines.base import ( # noqa: E402 + EngineRequest, + FindingEvent, + NoticeEvent, + ProgressEvent, +) +from limier.engines.registry import moteur_pour # noqa: E402 +from limier.engines.username import permutations # noqa: E402 + +COULEURS = { + "confirmed": "\033[32m", # vert + "probable": "\033[33m", # jaune + "weak": "\033[90m", # gris +} +GRAS = "\033[1m" +NEUTRE = "\033[0m" + + +def afficher_resultat(evenement: FindingEvent, index: int) -> None: + couleur = COULEURS.get(evenement.confidence.value, "") + print( + f"\n{couleur}{GRAS}[{index:>3}] {evenement.source}{NEUTRE}" + f" {couleur}{evenement.confidence.value}{NEUTRE}" + f" {int(evenement.score * 100)} %" + ) + if evenement.url: + print(f" {evenement.url}") + + signaux = [c for c, v in evenement.signals.items() if v is True] + if signaux: + print(f" signaux : {', '.join(signaux)}") + + for cle, valeur in list(evenement.profile.items())[:6]: + texte = str(valeur) + if len(texte) > 100: + texte = texte[:100] + "…" + print(f" {cle} : {texte}") + + +async def principal() -> int: + if len(sys.argv) < 3: + print("Usage : essai.py ", file=sys.stderr) + return 2 + + genre, terme = sys.argv[1], " ".join(sys.argv[2:]) + try: + kind = SearchKind(genre) + except ValueError: + print(f"Type inconnu : {genre}", file=sys.stderr) + return 2 + + moteur = moteur_pour(kind) + if moteur is None: + print(f"Aucun moteur actif pour « {genre} ».", file=sys.stderr) + return 1 + + variantes = [] + if kind is SearchKind.NAME: + variantes = permutations.generer(terme, 8) + print(f"{GRAS}Variantes déduites :{NEUTRE} {', '.join(variantes)}") + + requete = EngineRequest(kind=kind, term=terme, variants=variantes) + print(f"{GRAS}Moteur :{NEUTRE} {moteur.name} {GRAS}Terme :{NEUTRE} {terme}") + print(f"{GRAS}Unités de travail prévues :{NEUTRE} {moteur.estimate_total(requete)}") + print("-" * 70) + + debut = time.monotonic() + trouves = 0 + comptes = {"confirmed": 0, "probable": 0, "weak": 0} + + async for evenement in moteur.run(requete): + if isinstance(evenement, FindingEvent): + trouves += 1 + comptes[evenement.confidence.value] += 1 + afficher_resultat(evenement, trouves) + elif isinstance(evenement, NoticeEvent): + marque = {"info": "·", "warning": "!", "error": "×"}[evenement.level] + print(f"\n {marque} {evenement.message}") + elif isinstance(evenement, ProgressEvent) and evenement.total: + pourcent = int(evenement.done / evenement.total * 100) + print( + f"\r {evenement.done}/{evenement.total} ({pourcent} %) " + f"{evenement.label or ''} ", + end="", + flush=True, + ) + + duree = time.monotonic() - debut + print("\n" + "-" * 70) + print( + f"{GRAS}{trouves} résultat(s) en {duree:.1f} s{NEUTRE} — " + f"{COULEURS['confirmed']}{comptes['confirmed']} confirmés{NEUTRE}, " + f"{COULEURS['probable']}{comptes['probable']} probables{NEUTRE}, " + f"{COULEURS['weak']}{comptes['weak']} faibles{NEUTRE}" + ) + return 0 + + +if __name__ == "__main__": + try: + sys.exit(asyncio.run(principal())) + except KeyboardInterrupt: + print("\nInterrompu.") + sys.exit(130) diff --git a/deploy/essai/nginx-essai.conf b/deploy/essai/nginx-essai.conf new file mode 100644 index 0000000..505ad38 --- /dev/null +++ b/deploy/essai/nginx-essai.conf @@ -0,0 +1,34 @@ +# Configuration nginx d'essai : sert l'interface ET relaie /api. +# +# En production, Traefik arbitre entre les deux par priorité de routeur et cette +# configuration n'existe pas. Ici on a besoin d'une origine unique, sinon le +# navigateur n'enverrait pas le cookie de session à l'API. + +server { + listen 8080; + server_name _; + root /usr/share/nginx/html; + index index.html; + + location /api/ { + proxy_pass http://essai-api:8000; + proxy_http_version 1.1; + 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; + + # Indispensable pour le flux SSE de progression : sans ces trois + # directives, nginx met la réponse en tampon et l'avancement + # n'arriverait qu'à la fin de la recherche. + proxy_buffering off; + proxy_cache off; + proxy_read_timeout 3600s; + } + + location / { + try_files $uri $uri/ /index.html; + } + + access_log off; +} diff --git a/docs/02-deploiement.md b/docs/02-deploiement.md index d461797..ea306ff 100644 --- a/docs/02-deploiement.md +++ b/docs/02-deploiement.md @@ -39,11 +39,20 @@ cp .env.example .env Générer les trois secrets : ```bash -echo "POSTGRES_PASSWORD=$(openssl rand -base64 32)" -echo "LIMIER_SESSION_SECRET=$(openssl rand -hex 32)" -echo "LIMIER_IDENTIFIER_HASH_PEPPER=$(openssl rand -hex 32)" +cd /opt/limier +sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -hex 24)|" .env +sed -i "s|^LIMIER_SESSION_SECRET=.*|LIMIER_SESSION_SECRET=$(openssl rand -hex 32)|" .env +sed -i "s|^LIMIER_IDENTIFIER_HASH_PEPPER=.*|LIMIER_IDENTIFIER_HASH_PEPPER=$(openssl rand -hex 32)|" .env ``` +Les trois secrets sont écrits directement dans `.env` sans passer par le +terminal : rien ne reste dans l'historique du shell. + +> **Hexadécimal et non base64 pour `POSTGRES_PASSWORD`.** Ce mot de passe est +> injecté tel quel dans l'URL de connexion. Les caractères `/` et `+` que +> produit base64 rendent cette URL invalide, et l'API refuse alors de démarrer +> sur une erreur de validation peu explicite. + > **Le poivre ne se change pas à la légère.** Toutes les empreintes > d'identifiants en dépendent. Le modifier rend inopérants les blocages > d'effacement déjà enregistrés : les empreintes ne correspondront plus. diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 00f1c4a..ab66c13 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -11,26 +11,34 @@ COPY tsconfig*.json vite.config.ts index.html ./ COPY src ./src RUN npm run build +# --------------------------------------------------------------------------- # Étape 2 : service des fichiers statiques -FROM nginx:1.27-alpine +# +# Image « unprivileged » officielle plutôt que nginx:alpine retouché au sed. +# Elle écoute déjà sur 8080, tourne en UID 101, place le PID et les répertoires +# temporaires dans /tmp, et supprime la directive `user` de nginx.conf. +# +# Motif du changement : nginx 1.27.5 a déplacé le PID de /var/run/nginx.pid vers +# /run/nginx.pid. Un sed sur l'ancien chemin ne correspond plus à rien, la +# substitution passe en silence, et nginx échoue au démarrage sur +# « open() "/run/nginx.pid" failed (13: Permission denied) ». Le projet nginx +# amont a rencontré exactement ce cas et a dû corriger son propre sed : autant +# s'appuyer sur leur image plutôt que refaire le travail à côté. +FROM nginxinc/nginx-unprivileged:1.27-alpine -ENV TZ=Europe/Paris -RUN apk add --no-cache tzdata curl \ - && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime +USER root +RUN apk add --no-cache tzdata \ + && ln -snf /usr/share/zoneinfo/Europe/Paris /etc/localtime \ + && echo "Europe/Paris" > /etc/timezone -COPY --from=build /app/dist /usr/share/nginx/html +COPY --from=build --chown=101:101 /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf -# nginx:alpine tourne en root pour lier le port 80 ; on écoute sur 8080 et on -# bascule sur l'utilisateur nginx, non privilégié. -RUN sed -i 's|^user .*|# user directive retiree : execution non privilegiee|' /etc/nginx/nginx.conf \ - && sed -i 's|/var/run/nginx.pid|/tmp/nginx.pid|' /etc/nginx/nginx.conf \ - && chown -R nginx:nginx /usr/share/nginx/html /var/cache/nginx +USER 101 -USER nginx EXPOSE 8080 +# wget (busybox) et non curl : l'image Alpine ne l'embarque pas, et l'installer +# pour une sonde de santé alourdirait l'image sans raison. HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ - CMD curl -fsS http://127.0.0.1:8080/ >/dev/null || exit 1 - -CMD ["nginx", "-g", "daemon off;"] + CMD wget -q -O /dev/null http://127.0.0.1:8080/ || exit 1 diff --git a/frontend/package.json b/frontend/package.json index 4f310f6..7dbe490 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "limier-frontend", - "version": "1.0.0", + "version": "1.0.1", "private": true, "type": "module", "scripts": {