Sign inSign up

tvnlabs/tvnipam-gateway

By tvnlabs

•Updated about 1 month ago

Nginx access gateway for tvnIPAM

Image
0

1.6K

tvnlabs/tvnipam-gateway repository overview

⁠tvnIPAM

tvnIPAM è un'applicazione self-hosted per la gestione centralizzata di ambienti, sezioni, subnet e indirizzi IP.

La distribuzione pubblica supportata utilizza esclusivamente queste immagini Docker Hub:

docker.io/tvnlabs/tvnipam-web:v0.8.0
docker.io/tvnlabs/tvnipam-api:v0.8.0
docker.io/tvnlabs/tvnipam-gateway:v0.8.0

L'installazione richiede soltanto due file:

.env
compose.yaml

Non sono richiesti clone del repository, script di installazione o file di configurazione Nginx esterni.

⁠Indice

⁠Architettura

Lo stack è composto da sei container:

ContainerFunzione
postgresConserva i dati applicativi
api-migrateApplica le migrazioni del database e termina
apiGestisce dati, utenti, rete, DNS e configurazione
webFornisce l'interfaccia web
gatewayGestisce HTTP, reverse proxy e HTTPS
update-checkerRileva le release e avvia il runner temporaneo degli aggiornamenti gestiti

api-migrate applica le migrazioni Prisma prima dell'avvio dell'API. Il servizio api viene avviato soltanto dopo la conclusione positiva delle migrazioni.

Il gateway Nginx è pubblicato come immagine separata e gestisce:

  • accesso HTTP iniziale e di recupero;
  • utilizzo dietro reverse proxy esterno;
  • TLS integrato;
  • reload controllato della configurazione TLS.

Soltanto update-checker monta il socket Docker. L'API usa la stessa immagine, ma non ha accesso al socket. Per Docker rootless impostare DOCKER_SOCKET_PATH al socket dell'utente, ad esempio /run/user/1000/docker.sock.

⁠1. Creazione della directory

Creare una directory dedicata ed entrarvi:

mkdir -p tvnipam
cd tvnipam

⁠2. File .env

Creare .env con il seguente contenuto:

# Managed release channel. Use vX.Y.Z to pin a version.
TVNIPAM_VERSION=latest

# Optional host paths used by managed in-app updates.
TVNIPAM_DEPLOYMENT_HOST_PATH=.
TVNIPAM_UPDATE_DATA_HOST_PATH=./data/update
TVNIPAM_TLS_HOST_PATH=./config/tls
DOCKER_SOCKET_PATH=/var/run/docker.sock

# HTTP is the initial entry point. Access mode and public URL are configured in the app.
PUBLIC_BIND=0.0.0.0
PUBLIC_PORT=6969

# The HTTPS port is reserved from the first start and opens after TLS is enabled in the app.
HTTPS_BIND=0.0.0.0
HTTPS_PORT=443

# Internal gateway/web/API authentication. Never configure this value on an external proxy.
TVNIPAM_TRUST_TOKEN=change-me-generate-a-long-random-trust-token
# Emergency recovery override. Set true, then run docker compose up -d to force HTTP on.
TVNIPAM_FORCE_HTTP=false

POSTGRES_DB=tvnipam
POSTGRES_USER=tvnipam
POSTGRES_PASSWORD=change-me-generate-a-long-random-password

JWT_SECRET=change-me-generate-a-long-random-secret
EMAIL_ENCRYPTION_KEY=change-me-generate-a-long-random-secret

Prima dell'avvio sostituire tutti i valori di esempio relativi a password, token e chiavi con valori casuali robusti.

È possibile generarli, ad esempio, con:

openssl rand -hex 24
openssl rand -hex 48

latest abilita il canale gestito predefinito. È possibile usare un tag vX.Y.Z per fissare esplicitamente una release.

⁠3. File compose.yaml

Creare compose.yaml con il seguente contenuto:

name: tvnipam

x-api-environment: &api-environment
  NODE_ENV: production
  TVNIPAM_ACCESS_MODE: ${TVNIPAM_ACCESS_MODE:-}
  APP_BASE_URL: ${APP_BASE_URL:-http://localhost:6969}
  API_PORT: "3001"
  DATABASE_URL: postgresql://${POSTGRES_USER:-tvnipam}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@postgres:5432/${POSTGRES_DB:-tvnipam}
  PERSISTENCE_DRIVER: prisma
  JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}
  EMAIL_ENCRYPTION_KEY: ${EMAIL_ENCRYPTION_KEY:?EMAIL_ENCRYPTION_KEY is required}
  TVNIPAM_TRUST_TOKEN: ${TVNIPAM_TRUST_TOKEN:?TVNIPAM_TRUST_TOKEN is required}
  TVNIPAM_VERSION: ${TVNIPAM_VERSION:?TVNIPAM_VERSION is required}
  TVNIPAM_UPDATE_MANAGED: "true"
  TVNIPAM_UPDATE_CHANNEL: ${TVNIPAM_UPDATE_CHANNEL:-}
  TVNIPAM_UPDATE_STATE_DIR: /var/lib/tvnipam/update
  TVNIPAM_FORCE_HTTP: ${TVNIPAM_FORCE_HTTP:-false}
  TVNIPAM_TLS_DIR: /etc/tvnipam/tls
  DB_HOST: postgres
  DB_PORT: "5432"

services:
  postgres:
    container_name: tvnipam-postgres
    image: docker.io/library/postgres:16
    environment:
      POSTGRES_DB: ${POSTGRES_DB:-tvnipam}
      POSTGRES_USER: ${POSTGRES_USER:-tvnipam}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-tvnipam} -d ${POSTGRES_DB:-tvnipam}"]
      interval: 5s
      timeout: 3s
      retries: 20
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  api-migrate:
    container_name: tvnipam-api-migrate
    image: docker.io/tvnlabs/tvnipam-api:${TVNIPAM_VERSION:?TVNIPAM_VERSION is required}
    command: ["apps/api/node_modules/.bin/prisma", "migrate", "deploy", "--schema", "apps/api/prisma/schema.prisma"]
    environment: *api-environment
    depends_on:
      postgres:
        condition: service_healthy
    restart: "no"

  api:
    container_name: tvnipam-api
    image: docker.io/tvnlabs/tvnipam-api:${TVNIPAM_VERSION:?TVNIPAM_VERSION is required}
    cap_add:
      - NET_ADMIN
      - NET_RAW
    environment: *api-environment
    depends_on:
      postgres:
        condition: service_healthy
      api-migrate:
        condition: service_completed_successfully
    volumes:
      - type: bind
        source: ${TVNIPAM_UPDATE_DATA_HOST_PATH:-./data/update}
        target: /var/lib/tvnipam/update
      - type: bind
        source: ${TVNIPAM_TLS_HOST_PATH:-./config/tls}
        target: /etc/tvnipam/tls
        bind:
          create_host_path: true
    restart: unless-stopped

  web:
    container_name: tvnipam-web
    image: docker.io/tvnlabs/tvnipam-web:${TVNIPAM_VERSION:?TVNIPAM_VERSION is required}
    environment:
      NODE_ENV: production
      APP_PORT: "3000"
      API_ORIGIN: http://api:3001
      TVNIPAM_TRUST_TOKEN: ${TVNIPAM_TRUST_TOKEN:?TVNIPAM_TRUST_TOKEN is required}
    depends_on:
      - api
    restart: unless-stopped

  gateway:
    container_name: tvnipam-gateway
    image: docker.io/tvnlabs/tvnipam-gateway:${TVNIPAM_VERSION:?TVNIPAM_VERSION is required}
    environment:
      NGINX_ENVSUBST_FILTER: ^TVNIPAM_TRUST_TOKEN$
      TVNIPAM_TRUST_TOKEN: ${TVNIPAM_TRUST_TOKEN:?TVNIPAM_TRUST_TOKEN is required}
    ports:
      - "${PUBLIC_BIND:-127.0.0.1}:${PUBLIC_PORT:-6969}:8080"
      - "${HTTPS_BIND:-0.0.0.0}:${HTTPS_PORT:-443}:443"
    volumes:
      - type: bind
        source: ${TVNIPAM_TLS_HOST_PATH:-./config/tls}
        target: /etc/tvnipam/tls
        read_only: true
        bind:
          create_host_path: true
    depends_on:
      - web
    healthcheck:
      test: ["CMD-SHELL", "wget -q -O - http://127.0.0.1:8080/api/health >/dev/null"]
      interval: 10s
      timeout: 3s
      retries: 12
    restart: unless-stopped

  update-checker:
    container_name: tvnipam-update-checker
    image: docker.io/tvnlabs/tvnipam-api:${TVNIPAM_VERSION:?TVNIPAM_VERSION is required}
    command: ["node", "apps/api/dist/src/modules/system/update-checker.js"]
    environment:
      TVNIPAM_VERSION: ${TVNIPAM_VERSION:?TVNIPAM_VERSION is required}
      TVNIPAM_UPDATE_CHANNEL: ${TVNIPAM_UPDATE_CHANNEL:-}
      TVNIPAM_UPDATE_STATE_DIR: /var/lib/tvnipam/update
      TVNIPAM_UPDATE_COMPOSE_FILE: compose.yaml
    volumes:
      - type: bind
        source: ${TVNIPAM_UPDATE_DATA_HOST_PATH:-./data/update}
        target: /var/lib/tvnipam/update
      - type: bind
        source: ${TVNIPAM_DEPLOYMENT_HOST_PATH:-.}
        target: /deployment
      - type: bind
        source: ${TVNIPAM_TLS_HOST_PATH:-./config/tls}
        target: /etc/tvnipam/tls
      - type: bind
        source: ${DOCKER_SOCKET_PATH:-/var/run/docker.sock}
        target: /var/run/docker.sock
    restart: unless-stopped

volumes:
  postgres_data:

Il Compose crea automaticamente ./config/tls; creare inoltre ./data/update con permessi 0700 prima dell'avvio. Il socket Docker è montato soltanto nel servizio update-checker.

Prima del primo avvio creare data/update con mkdir -p data/update e chmod 700 data/update. Non è necessario eseguire manualmente migrazioni Prisma.

⁠4. Validazione e avvio

Dalla directory contenente .env e compose.yaml:

docker compose config --quiet
docker compose pull
docker compose up -d

Controllare lo stato:

docker compose ps -a

Verificare l'API attraverso il gateway HTTP:

curl -fsS http://127.0.0.1:6969/api/health

Risposta attesa:

{"status":"ok"}

api-migrate deve terminare con exit code 0. Gli altri cinque servizi devono restare avviati e il gateway deve diventare healthy.

⁠Modalità HTTP diretta

L'HTTP è il punto di ingresso iniziale e di recupero.

Con:

PUBLIC_BIND=127.0.0.1
PUBLIC_PORT=6969

il servizio è raggiungibile soltanto dalla macchina Docker.

Per esporlo direttamente sulla rete impostare un bind coerente con la propria configurazione, ad esempio:

PUBLIC_BIND=0.0.0.0
PUBLIC_PORT=6969

Valutare firewall e segmentazione di rete prima di esporre la porta.

⁠Reverse proxy esterno

Per usare un reverse proxy esterno:

  1. mantenere attivo l'ingresso HTTP del gateway;
  2. configurare il proxy verso http://HOST_DOCKER:PUBLIC_PORT;
  3. configurare dall'applicazione l'URL pubblico e i reverse proxy attendibili;
  4. verificare login, cookie e health check attraverso il dominio pubblico.

Le impostazioni di accesso sono gestite da:

Gestione app → Sistema

Il reverse proxy esterno non deve montare i certificati interni di tvnIPAM e non richiede un header segreto applicativo.

⁠TLS integrato

Il gateway espone anche la porta HTTPS configurata da:

HTTPS_BIND
HTTPS_PORT

Il primo accesso e la configurazione iniziale avvengono tramite HTTP. I certificati TLS integrati vengono poi configurati dall'interfaccia di amministrazione.

API e gateway condividono la directory:

./config/tls

L'API la monta in lettura e scrittura. Il gateway la monta in sola lettura.

Il watcher integrato verifica la nuova configurazione con nginx -t, mantiene la configurazione precedente in caso di errore e ricarica Nginx soltanto dopo una validazione positiva.

TVNIPAM_FORCE_HTTP=true deve essere usato soltanto come modalità temporanea di recupero.

⁠Persistenza TLS

config/tls è un bind mount host, non un volume Docker.

La directory e i certificati sopravvivono a:

docker compose down
docker compose down -v

Non eliminare manualmente config/tls durante aggiornamenti o recreate.

L'API può proteggere la directory come root:root 0700. In tal caso un utente host non privilegiato potrebbe non riuscire a leggerne il contenuto: backup, verifiche e ripristini devono essere eseguiti con privilegi adeguati.

⁠Backup

Prima di aggiornamenti o modifiche importanti eseguire almeno il backup di:

  • database PostgreSQL;
  • file .env;
  • file compose.yaml;
  • directory config/tls.

Esempio di backup TLS:

sudo tar -C . -czf tvnipam-config-tls.tar.gz config/tls

Conservare il backup fuori dalla directory dell'installazione.

⁠Aggiornamento

Da Gestione app → Sistema usare Controlla ora e quindi Aggiorna ora. Il checker scarica le immagini, salva .env, PostgreSQL e config/tls, ricrea lo stack e applica automaticamente il rollback se il nuovo healthcheck fallisce. I backup restano in data/update/update-backups/.

Il pulsante è disponibile soltanto per utenti interattivi con permesso system.write, quando l'installazione è gestita, è stata rilevata l'ultima release stabile e non sono attive scansioni IPAM o altre operazioni di update. Durante l'aggiornamento l'interfaccia mostra fase, avanzamento e byte scaricati; una temporanea indisponibilità dell'API durante il riavvio è prevista.

Prima di modificare dati il runner verifica che API, web e gateway appartengano alla stessa release. Lo stato terminale e i backup vengono conservati per la diagnosi e non sono eliminati automaticamente.

L'aggiornamento manuale resta disponibile:

docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps

Non è necessario eseguire separatamente le migrazioni: api-migrate viene eseguito dal Compose e l'API ne attende il completamento positivo.

⁠Bootstrap delle installazioni esistenti

Le installazioni create prima degli aggiornamenti gestiti richiedono una sola modifica manuale del deployment:

  1. se il file precedente si chiama compose.yml, rinominarlo in compose.yaml;
  2. sostituire compose.yaml con quello documentato sopra;
  3. aggiungere a .env TVNIPAM_DEPLOYMENT_HOST_PATH, TVNIPAM_UPDATE_DATA_HOST_PATH, TVNIPAM_TLS_HOST_PATH e DOCKER_SOCKET_PATH;
  4. creare data/update con permessi 0700;
  5. eseguire docker compose config --quiet, docker compose pull e docker compose up -d.

Dopo questo bootstrap gli aggiornamenti successivi possono essere avviati dall'interfaccia. L'accesso al socket equivale al controllo del Docker Engine: proteggere la directory di installazione e limitare l'accesso amministrativo.

Se il bootstrap è stato eseguito con una versione fissata, è possibile passare al canale gestito modificando .env in TVNIPAM_VERSION=latest e ripetendo i tre comandi di validazione, pull e avvio indicati sopra.

⁠Rollback

Per tornare alla versione precedente:

  1. verificare la compatibilità dello schema PostgreSQL;
  2. ripristinare il database quando necessario;
  3. impostare in .env il tag precedente;
  4. rieseguire il Compose.
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps

Un rollback automatico da latest fissa nel file .env la precedente release vX.Y.Z, impedendo di reinstallare la versione non sana al riavvio.

⁠Arresto

Per arrestare lo stack mantenendo database e certificati:

docker compose down

Anche docker compose down -v non elimina config/tls, perché si tratta di un bind mount. Può però eliminare i volumi Docker dichiarati dal Compose, incluso il volume del database: non usarlo senza un backup PostgreSQL verificato.

⁠Immagini

Web:

docker.io/tvnlabs/tvnipam-web:v0.8.0

API e migrazioni:

docker.io/tvnlabs/tvnipam-api:v0.8.0

Gateway:

docker.io/tvnlabs/tvnipam-gateway:v0.8.0

Tag summary

Content type

Image

Digest

sha256:d776d4368…

Size

27.2 MB

Last updated

about 1 month ago

docker pull tvnlabs/tvnipam-gateway