Vai al contenuto
Q
QuoteNode

Installation

Aggiornamento di QuoteNode

Come verificare le nuove versioni, aggiornare al pacchetto di una nuova release e tornare indietro in sicurezza.

Aggiornare QuoteNode

QuoteNode verifica automaticamente la disponibilità di nuove release. Quando è disponibile una versione più recente, il pannello di amministrazione mostra una notifica con l’etichetta della release e un link alle note di rilascio.

Ogni release è pubblicata come pacchetto di distribuzione: docker-compose.yml (e docker-compose.coolify.yml) con le immagini della release fissate tramite digest, env.example, release.json e gli strumenti di operator/. Aggiornare significa sostituire il file Compose con quello del pacchetto successivo. La release attuale è v0.9.8-alpha (pacchetto).

Il modo di aggiornare dipende da come è stato installato QuoteNode. La lista di controllo e i comandi seguenti valgono per una directory di installazione (server, LAN, portatile o una cartella sul NAS con docker-compose.yml e .env). Uno stack Portainer non ha questa directory: vai a Stack Portainer. Coolify: vai a Coolify.

Problema noto in v0.9.5-alpha: destinazione di backup di esempio

Il file env.example di v0.9.5-alpha contiene una riga di esempio attiva, BACKUP_RCLONE_REMOTE=s3:mybucket/backups. Quella destinazione non è configurata: se la riga arriva nelle tue impostazioni, ogni backup fallisce e un caricamento fallito non lascia alcuna copia locale di quel backup. Le impostazioni di queste guide non la contengono mai; controlla l’installazione se hai creato .env da env.example o vi hai aggiunto impostazioni da quel file durante un aggiornamento.

In una directory di installazione, commenta esattamente quella riga di esempio (una destinazione reale resta invariata) e ricrea i container:

# Run in Bash (for example Linux, Git Bash or WSL); other shells can edit the exact placeholder manually.
(
  set -eu
  umask 077
  temporary_env="$(mktemp .env.backup-remote.XXXXXX)"
  trap 'rm -f "$temporary_env"' EXIT
  carriage_return="$(printf '\r')"
  # Match only the published placeholder, with either LF or Windows CRLF line endings.
  sample_pattern="^BACKUP_RCLONE_REMOTE=s3:mybucket/backups${carriage_return}\{0,1\}$"
  sed "s|${sample_pattern}|# &|" .env > "$temporary_env"
  if LC_ALL=C grep -Eq "^BACKUP_RCLONE_REMOTE=s3:mybucket/backups${carriage_return}?$" "$temporary_env"; then
    echo "Sample backup remote is still active; settings were not replaced." >&2
    exit 1
  else
    match_status=$?
    [ "$match_status" -eq 1 ] || exit "$match_status"
  fi
  # Keep real remote settings unchanged; publish a changed file atomically with private permissions.
  if ! cmp -s .env "$temporary_env"; then
    mv "$temporary_env" .env
  fi
  docker compose up -d
)

In Portainer, elimina la variabile dello stack BACKUP_RCLONE_REMOTE se ha quel valore di esempio, poi aggiorna lo stack. La definizione Coolify di v0.9.5-alpha non passa questa variabile all’applicazione; elimina il valore di esempio dalla risorsa prima di aggiornare a una release successiva.

I backup restano allora nel volume dei backup. Avvia un backup dal pannello di amministrazione (Admin → Security → Backup), verifica che termini correttamente e predisponi una copia fuori dal server: una destinazione rclone configurata o copie regolari degli archivi su un’altra macchina (Backup e ripristino).

Passare a PostgreSQL 18

I file Compose usano già postgres:18-alpine, quindi le nuove installazioni non richiedono nulla. Se una versione alpha precedente girava su PostgreSQL 16, migra i dati una volta — un server PostgreSQL 18 non si avvia su una directory dati più vecchia e l’applicazione non la riscrive mai automaticamente. Segui la procedura dedicata e sicura: Migrare i dati a PostgreSQL 18 (da riga di comando o solo da interfaccia, per piattaforma).

Come funziona il controllo della versione

L’interfaccia di amministrazione scarica https://quotenode.dev/releases/latest.json all’accesso di un amministratore. È una richiesta GET di sola lettura, senza autenticazione; nessun dato della tua istanza viene inviato. Se il manifest non è raggiungibile, il controllo fallisce in silenzio e il pannello funziona normalmente.

Il controllo e l’URL del manifest fanno parte dell’interfaccia web già costruita. Impostare VITE_RELEASE_CHECK_ENABLED o VITE_RELEASE_MANIFEST_URL in .env o in Coolify non ha effetto su una release; questi valori valgono solo se costruisci tu stesso l’immagine del frontend dai sorgenti. Per evitare che un’installazione contatti quotenode.dev, blocca quell’indirizzo nella tua rete.

Lista di controllo prima dell’aggiornamento

Per una directory di installazione; Portainer e Coolify hanno sezioni proprie più sotto.

  1. Annota la release attuale: release.json nella directory di installazione, oppure Admin > Licenza.
  2. Copia .env fuori dal server — contiene segreti che non si possono rigenerare (soprattutto DB_ENCRYPTION_KEY).
  3. Scarica il nuovo pacchetto accanto all’installazione. Non cambia nulla di ciò che è in esecuzione:
mkdir -p ../next && cd ../next
curl -fsSLO https://quotenode.dev/releases/v0.9.8-alpha/quotenode-deploy-v0.9.8-alpha.tar.gz
tar -xzf quotenode-deploy-v0.9.8-alpha.tar.gz --strip-components=1
cd -
# Impostazioni aggiunte o rimosse dalla nuova release? Confronta il tuo .env con il nuovo modello.
diff <(grep -o '^[A-Z_]*=' .env | sort) <(grep -o '^[A-Z_]*=' ../next/env.example | sort)
  1. Aggiungi a .env le impostazioni richieste dalla nuova release (il confronto qui sopra le elenca; installazioni precedenti ai pacchetti di release: vedi Installazioni precedenti ai pacchetti di release). L’installazione in esecuzione non le usa ancora.
  2. Crea il checkpoint di aggiornamento e un backup verificato con lo strumento del nuovo pacchetto. Non cambia nulla di ciò che è in esecuzione e si ferma al primo errore:
BACKUP_ARCHIVE_ENCRYPTION_MODE=AGE_RECIPIENT BACKUP_AGE_RECIPIENT=age1... \
  ../next/operator/upgrade.sh prepare --export-to ../quotenode-backups

Il checkpoint (in .quotenode-upgrade/, usato solo da questa installazione) registra docker-compose.yml, .env e release.json installati, l’identità delle immagini in esecuzione e lo stato dello schema del database. Il backup viene creato con gli strumenti della nuova release sul progetto Compose e sui volumi di questa installazione, resta locale in questa esecuzione anche se sono configurati backup remoti e viene conservato in ../quotenode-backups solo quando il suo SHA-256 coincide. Copia quella directory fuori dal server prima di proseguire. Il destinatario age si trova nel tuo Recovery Kit (Backup e ripristino).

  1. Se i backup pianificati sono attivi, verifica anche che l’ultimo sia riuscito (pannello di amministrazione).

Procedura di aggiornamento

Docker Compose (server, LAN, portatile, cartella sul NAS)

Dopo la lista di controllo, esegui nella directory di installazione, così il progetto Compose e i suoi volumi restano gli stessi:

../next/operator/upgrade.sh apply

upgrade.sh apply scarica prima tutte le immagini della nuova release e si ferma al primo errore: se un download fallisce, l’installazione continua a funzionare senza modifiche. Solo dopo installa docker-compose.yml, release.json, env.example e operator/ dal pacchetto, avvia la nuova versione e attende che sia in salute. Le migrazioni del database vengono eseguite automaticamente all’avvio del nuovo backend. È richiesto Docker Compose 2.17 o successivo.

Stack Portainer

upgrade.sh richiede una directory di installazione, quindi uno stack Portainer si aggiorna in Portainer:

  1. Verifica che l’ultimo backup pianificato sia riuscito (pannello di amministrazione), proteggi i volumi dello stack con lo strumento di snapshot o di backup della tua piattaforma e salva una copia della definizione attuale dello stack e delle sue variabili d’ambiente.
  2. Apri l’Editor dello stack e sostituisci la definizione con il blocco seguente: l’adattamento per Portainer del docker-compose.yml della release, lo stesso blocco di Installare con Portainer. Non incollare il file originale del pacchetto: legge .env, che Portainer non ha.
  3. Mantieni il nome dello stack e le sue variabili d’ambiente (stack.env); aggiungi le impostazioni richieste dalla nuova release (confronta con il suo env.example).
  4. Fai clic su Update the stack con il download delle immagini attivo. Le migrazioni del database vengono eseguite all’avvio del nuovo backend.
# Portainer Web editor adaptation of the release docker-compose.yml: env_file reads stack.env (the stack's
# environment variables) instead of .env in postgres, backend and backup-worker. Images, services, ports and
# volumes are unchanged. For a folder-based installation use the unchanged file of the release package.
x-json-file-logging: &json-file-logging
  driver: json-file
  options:
    max-size: "${DOCKER_LOG_MAX_SIZE:-10m}"
    max-file: "${DOCKER_LOG_MAX_FILE:-5}"

# ==========================================================================
# QuoteNode — standalone deployment (docker compose)
# GENERATED by scripts/render-deployment.mjs — do not edit by hand.
# Release v0.9.8-alpha (commit ff74453ca68f3c40bd86a32f0b0b813aaffc7aea, build 28); platforms: linux/amd64.
# API image:      ghcr.io/lesisty7/quotenode/quotenode-api@sha256:0ed701f952c27ea0e1db168a00de75facb231f7c6d5f6b4f0f3b77ef98d4f140
# Frontend image: ghcr.io/lesisty7/quotenode/quotenode-frontend@sha256:40a1cdc4fca5cebd9f43d34daef4ba059a88000ff08af821e199566f07260606
#
# Settings: the .env file in this directory (start from env.example, the commented catalogue of every
# setting; postgres, backend and backup-worker read it). Start: docker compose up -d
# DOMAIN: public host name for automatic HTTPS, or :80 / http://<address> for plain HTTP on a trusted LAN.
# Only the caddy entry point publishes ports (HTTP_PORT/HTTPS_PORT, default 80/443).
# Upgrades: replace this file with the next release package version; volumes keep the data.
# ==========================================================================

services:
  postgres:
    # Database (PostgreSQL 18); internal network only, data in the database volume.
    image: postgres:18-alpine@sha256:77f585114c32fbca283dc835b0596f4e52b51b4c6662d7810b2f4084f60a1873
    # JIT is off by default: for this OLTP workload most queries fall below jit_above_cost,
    # so JIT compilation rarely helps and can add latency. Set PG_JIT=on to re-enable.
    command: ["postgres", "-c", "jit=${PG_JIT:-off}"]
    env_file: stack.env
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_INITDB_ARGS: "--data-checksums"
      # postgres:18 refuses to start on a bare /var/lib/postgresql/data mount (new default layout).
      # Pin PGDATA to the legacy path so the existing volume mount keeps working; major upgrades go
      # through a logical dump/restore, never an in-place upgrade of the data directory.
      PGDATA: /var/lib/postgresql/data
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d ${DB_NAME}"]
      interval: 10s
      timeout: 5s
      retries: 10
    # CPU ceilings are opt-in (*_CPUS): 0 = no ceiling, all host cores. Docker refuses a ceiling above the
    # host's core count, so a fixed default would stop the stack on smaller hosts (minimum: 2 cores).
    cpus: ${POSTGRES_CPUS:-0}
    # Ceiling, not a reservation: PG sits at tens of MB until working set/connections grow.
    # Default 512m fits the 4 GB-VM profile; raise POSTGRES_MEM_LIMIT for larger tiers.
    mem_limit: ${POSTGRES_MEM_LIMIT:-512m}
    restart: unless-stopped
    logging: *json-file-logging
    # No published host port: the database is reachable only on the internal network.

  gotenberg:
    # PDF rendering (Chromium) for the backend; internal network only, keeps no data.
    image: gotenberg/gotenberg:8@sha256:aa552cc115db488e0f0bcb07446aac13071ad51505b642c84bb894500907b42b
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:3000/health"]
      interval: 10s
      timeout: 5s
      retries: 5
    cpus: ${GOTENBERG_CPUS:-0}
    # Chromium PDF rendering: measured ~188 MiB peak rendering a real offer template, so
    # 448m keeps ~2.4x headroom. Freed budget goes to backup-worker (closer to its limit).
    mem_limit: ${GOTENBERG_MEM_LIMIT:-448m}
    restart: unless-stopped
    logging: *json-file-logging

  backend:
    # API server (Java): business logic and web jobs; uploads, PDFs and the GeoIP database live in volumes.
    image: ghcr.io/lesisty7/quotenode/quotenode-api@sha256:0ed701f952c27ea0e1db168a00de75facb231f7c6d5f6b4f0f3b77ef98d4f140
    # Time Docker gives the backend between SIGTERM and SIGKILL. 60 s = the SMTP handoff hard limit
    # (mail.handoff.deadline-ms + end-of-data-allowance-ms = 25 s) + 5 s to record its outcome + the HTTP
    # graceful drain phase (30 s). A ceiling, not a delay: an idle backend exits in seconds.
    stop_grace_period: 60s
    depends_on:
      postgres:
        condition: service_healthy
      gotenberg:
        condition: service_healthy
    env_file: stack.env
    environment:
      SPRING_PROFILES_ACTIVE: prod
      JOBS_MODE: web
      # The caddy edge below is the backend's only HTTP peer, so it is the trusted proxy by default (security
      # finding #80); without it every request would appear to come from the edge container. Override only
      # for a custom proxy chain.
      SECURITY_TRUSTED_PROXIES: ${SECURITY_TRUSTED_PROXIES:-caddy}
      BACKUP_LOCAL_DIR: /app/data/backups
    volumes:
      - backend_uploads:/app/data/uploads
      - backend_pdfs:/app/data/pdfs
      - backend_backups:/app/data/backups
      - backend_geoip:/app/data/geoip
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
      interval: 15s
      timeout: 10s
      retries: 5
      start_period: 45s
    cpus: ${BACKEND_CPUS:-0}
    # Heap auto-scales to 70% of this limit (MaxRAMPercentage); default 1536m → ~1 GB heap,
    # fits the 4 GB-VM profile. Raise BACKEND_MEM_LIMIT for heavier load (see resource docs).
    mem_limit: ${BACKEND_MEM_LIMIT:-1536m}
    restart: unless-stopped
    logging: *json-file-logging

  backup-worker:
    # Scheduled backups: same image as the backend, JOBS_MODE=backup-only; archives go to the backups volume.
    image: ghcr.io/lesisty7/quotenode/quotenode-api@sha256:0ed701f952c27ea0e1db168a00de75facb231f7c6d5f6b4f0f3b77ef98d4f140
    depends_on:
      postgres:
        condition: service_healthy
      backend:
        condition: service_healthy
    env_file: stack.env
    environment:
      SPRING_PROFILES_ACTIVE: prod
      JOBS_MODE: backup-only
      BACKUP_LOCAL_DIR: /app/data/backups
      # Worker runs pg_dump in a shell (out-of-JVM) and never does web/import heap work,
      # so it needs little heap. On this small 768m container the ~350 MB fixed non-heap
      # cost makes the global MaxRAMPercentage=70 (538 MB heap → 888 MB total) unsafe.
      # Cap heap lower so heap_max + non-heap stays well under the limit.
      JAVA_OPTS: "-XX:MaxRAMPercentage=45.0 -XX:+UseG1GC -XX:G1PeriodicGCInterval=300000"
    volumes:
      - backend_uploads:/app/data/uploads
      - backend_pdfs:/app/data/pdfs
      - backend_backups:/app/data/backups
      - backend_geoip:/app/data/geoip
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
      interval: 15s
      timeout: 10s
      retries: 5
      # JVM boots a large Spring context (CPU-bound); the grace window must outlast
      # cold start to avoid a false-unhealthy restart loop under load.
      start_period: 300s
    # CPU is a ceiling (idle cost ~0); give the worker enough to boot fast and to run
    # pg_dump + age-encryption/compression bursts without throttling. Idles near zero CPU.
    cpus: ${WORKER_CPUS:-0}
    # Default 832m: measured backup peak (JVM idle + pg_dump + tar + gzip) is ~607 MiB, so
    # this keeps a ~27% margin. Do NOT set WORKER_MEM_LIMIT below ~768m or backups risk OOM.
    mem_limit: ${WORKER_MEM_LIMIT:-832m}
    restart: unless-stopped
    logging: *json-file-logging

  frontend:
    # Web UI: the static build served by Caddy, reached through the caddy entry point.
    image: ghcr.io/lesisty7/quotenode/quotenode-frontend@sha256:40a1cdc4fca5cebd9f43d34daef4ba059a88000ff08af821e199566f07260606
    depends_on:
      backend:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:80/"]
      interval: 15s
      timeout: 5s
      retries: 3
    cpus: ${FRONTEND_CPUS:-0}
    # Prod frontend is Caddy serving the static build (measured ~46 MiB peak under load); 96m is ample.
    # CPU is a free ceiling, so headroom for concurrent connections costs nothing at idle.
    mem_limit: ${FRONTEND_MEM_LIMIT:-96m}
    restart: unless-stopped
    logging: *json-file-logging

  caddy:
    # Entry point: the only published ports (HTTP_PORT/HTTPS_PORT, default 80/443), TLS for DOMAIN, routing, security headers.
    image: ghcr.io/lesisty7/quotenode/quotenode-frontend@sha256:40a1cdc4fca5cebd9f43d34daef4ba059a88000ff08af821e199566f07260606
    # The released frontend image carries the edge config (frontend/caddy/Caddyfile.edge) and the Cloudflare
    # ranges, so the edge needs no host files. Same image digest as the frontend service.
    command: ["caddy", "run", "--config", "/etc/caddy/Caddyfile.edge", "--adapter", "caddyfile"]
    depends_on:
      backend:
        condition: service_healthy
      frontend:
        condition: service_healthy
    environment:
      # Site address for frontend/caddy/Caddyfile.edge: a public host name enables automatic HTTPS; ":80" or
      # "http://host" serves plain HTTP on a trusted LAN. Required: an empty site address is not a valid config.
      DOMAIN: ${DOMAIN:?set DOMAIN to the public host name, or :80 for plain HTTP on a LAN}
      # Optional: address(es) of an operator reverse proxy in front of this edge (default: trust none).
      EDGE_TRUSTED_PROXIES: ${EDGE_TRUSTED_PROXIES:-}
    ports:
      - "${HTTP_PORT:-80}:80"
      - "${HTTPS_PORT:-443}:443"
      - "${HTTPS_PORT:-443}:443/udp"      # HTTP/3 (QUIC)
    volumes:
      - caddy_data:/data
      - caddy_config:/config
    # caddy is the single ingress (TLS, HTTP/3/QUIC, proxying all traffic); give it
    # cores for handshake/encryption bursts under load. CPU idle cost ~0.
    cpus: ${CADDY_CPUS:-0}
    # 96m fits the 4 GB / light-traffic profile. Under heavy TLS load (many concurrent
    # handshakes, large QUIC buffers) raise CADDY_MEM_LIMIT — this ingress is untested at scale.
    mem_limit: ${CADDY_MEM_LIMIT:-96m}
    restart: unless-stopped
    logging: *json-file-logging

# Persistent data: database, uploads, generated PDFs, local backup archives, GeoIP database and the entry
# point's certificates/config. Docker prefixes each name with the Compose project name (by default the
# directory name), so keep the project name across upgrades.
volumes:
  postgres_data:
  backend_uploads:
  backend_pdfs:
  backend_backups:
  backend_geoip:
  caddy_data:
  caddy_config:

Per tornare indietro, ripristina il backup dei volumi insieme alla definizione dello stack salvata. Non avviare mai la definizione precedente su un database che la nuova release ha già migrato.

Coolify

Sostituisci la definizione Compose della risorsa con il docker-compose.coolify.yml del nuovo pacchetto (Edit Compose File) e distribuisci. Coolify scarica le nuove immagini prima di arrestare i container in esecuzione. Vedi Installazione con Coolify.

Installazioni precedenti ai pacchetti di release

Se hai installato QuoteNode con queste guide prima che esistessero i pacchetti di release (un docker-compose.yml scritto a mano con immagini :latest), aggiorna nella stessa directory con gli stessi comandi: upgrade.sh crea il backup con gli strumenti della nuova release sul progetto Compose e sui volumi della tua installazione, quindi prima non servono né una directory operator/ né un servizio di backup. Prima di prepare, aggiungi queste impostazioni a .env; l’installazione in esecuzione non le usa ancora:

  • DOMAIN ora configura il nuovo punto di ingresso (caddy): un nome host pubblico ottiene automaticamente HTTPS; per HTTP semplice in LAN o su un portatile usa DOMAIN=http://<indirizzo> (ad esempio http://192.168.1.20 o http://localhost).
  • Se le porte 80/443 sono occupate, imposta HTTP_PORT / HTTPS_PORT invece di modificare il file Compose.

Il pacchetto mantiene i nomi dei volumi delle guide precedenti (postgres_data, backend_uploads, backend_pdfs), quindi i tuoi dati vengono riutilizzati. Esegui upgrade.sh dalla stessa directory (o mantieni lo stesso nome dello stack in Portainer): con un altro nome di progetto partirebbe con volumi vuoti.

Se una migrazione blocca l’aggiornamento

Una migrazione può rifiutarsi di procedere quando trova dati che non può modificare da sola. Il backend allora non si avvia e quella migrazione non cambia nulla — viene annullata completamente e non lascia nulla da riparare nella cronologia delle migrazioni. Migrazioni precedenti dello stesso aggiornamento possono essere già state applicate, quindi il database si trova subito prima del passo rifiutato e non alla versione di partenza. Non c’è fretta e non c’è perdita di dati.

Leggi il motivo nel log:

docker compose logs backend | grep -i "cannot enforce"

Per le assegnazioni delle sezioni delle offerte, l’immagine include una riparazione guidata che funziona senza backend attivo — mostra le offerte interessate e ti lascia scegliere cosa farne. Vedi Risoluzione dei problemi di installazione.

Non usare flyway repair o baseline per superare una migrazione rifiutata. Non riparano i dati, e una migrazione bloccata non lascia nulla da riparare.

Poiché migrazioni precedenti possono essere già applicate, un avvio fallito da solo non consente mai di tornare alle immagini precedenti — vedi Tornare indietro.

Verifica dopo l’aggiornamento

  1. Apri /health — la risposta è UP.
  2. Apri /actuator/info: il suo commitSha coincide con il commitSha del nuovo release.json.
  3. Accedi e verifica la nuova versione in Admin > Licenza.
  4. Crea un’offerta di prova e genera un PDF.
  5. Apri un link pubblico per verificare l’instradamento.
  6. Se SMTP è configurato, invia un’e-mail di notifica di prova.

Tornare indietro

Non eseguire mai docker compose down -v — elimina tutti i dati, compreso il database.

upgrade.sh rollback torna alla definizione salvata da prepare solo quando è sicuro: il checkpoint deve appartenere a questa installazione, lo schema del database deve essere esattamente quello registrato — un avvio fallito non lo dimostra, migrazioni precedenti possono essere già confermate — e ogni immagine precedente deve essere ancora quella che era in esecuzione. Altrimenti rifiuta e non cambia nulla:

../next/operator/upgrade.sh rollback
  • Consentito: docker-compose.yml, .env e release.json salvati tornano e le immagini precedenti si avviano senza download; i servizi aggiunti dalla nuova release vengono rimossi, i volumi restano.
  • Rifiutato: non avviare a mano le immagini precedenti. Se una migrazione ha rifiutato, correggi nella nuova versione (vedi Se una migrazione blocca l’aggiornamento) oppure ripristina il backup precedente all’aggiornamento — database e file come un’unica unità — come descritto in Backup e ripristino. Il ripristino verifica l’archivio e la sua compatibilità prima di cambiare qualcosa e conserva una copia di sicurezza finché non ha verificato il risultato.
  • Le installazioni precedenti ai pacchetti di release tornano indietro allo stesso modo. Dopo un rifiuto, ripristina il backup da ../quotenode-backups con operator/restore.sh di questa release; la release aggiorna i dati ripristinati al suo avvio.

Formato della versione

QuoteNode usa il versionamento semantico con un suffisso di canale:

  • v0.9.0-alpha — sviluppo iniziale
  • v0.9.0-beta — beta pubblica
  • v0.9.0-rc — release candidate
  • v0.9.0 — release stabile

Un’etichetta di release non viene mai riutilizzata per altre immagini. release.json e https://quotenode.dev/releases/latest.json riportano versione, canale, etichetta, commit e digest delle immagini della release.

Last reviewed: Recently