Configurazione di distribuzione di Discourse secondo l'opinione di MKJ

Forse rispondendo alla mia stessa domanda, ecco alcune note derivanti dal tentativo di utilizzare Garage con la tua guida operativa:


1. Garage non supporta i “tag di autorizzazione” sui file (questa è la vera lacuna di Garage)

Amazon ti permette di contrassegnare ogni file come “pubblico” o “privato” individualmente. Garage non implementa questa funzionalità.

Discourse cerca di usarlo di default. L’aspetto subdolo: quando Discourse diceva “salva questo file, contrassegnalo come pubblico”, Garage accettava la richiesta e ignorava silenziosamente il tag. Quindi i caricamenti base sembravano funzionare correttamente, e si sarebbe rotto solo molto più tardi, la prima volta che qualcuno avesse reso un caricamento privato.

Soluzione: dire a Discourse di smettere di usare i tag (un’impostazione). Cloudflare R2 ha la stessa lacuna e riceve la stessa soluzione. Garage gestisce le autorizzazioni in modo autonomo, a livello di bucket, che è tutto ciò di cui abbiamo bisogno.


2. Discourse insiste nel nominare i bucket in un modo specifico (non è un difetto di Garage)

Discourse non dirà “il server su garage, bucket uploads”. Insiste su uploads.garage — il nome del bucket incollato all’inizio, come un sottodominio. E non c’è alcuna opzione per disabilitarlo.

Nessuna parte della nostra rete conosceva quel nome, quindi Discourse non poteva connettersi affatto — l’installazione è fallita a metà.

Soluzione: ho dato a Garage quello stile di denominazione e ho registrato i nomi. Due righe di configurazione.

Questa è una peculiarità nota di Discourse, non di Garage — è il motivo per cui lo storage di Oracle è nella lista ufficiale “non funzionante” di Discourse.


3. Le immagini avevano bisogno di un indirizzo web pubblico (nulla a che fare con Garage)

Discourse scrive l’indirizzo di ogni immagine nel post in modo permanente. Senza dirgli l’indirizzo pubblico in anticipo, ha salvato indirizzi interni raggiungibili solo dal nostro server — quindi ogni immagine sarebbe risultata rotta per i visitatori, per sempre, a meno che non ricostruissimo ogni post.

Soluzione: impostare l’indirizzo CDN prima del primo caricamento. Sarebbe stato identico su Amazon, R2, qualsiasi altro servizio.


Nota: ognuno di questi problemi è stato silenzioso. Nulla ha detto “non supportato”. Uno ha accettato la richiesta e l’ha ignorata, uno sembrava un errore di rete, uno sembrava funzionare perfettamente.

Quindi, solo alcune cose iniziali da tenere a mente per un nuovo utente che prova questo per la prima volta, e/o per qualcuno che cerca di seguire la guida operativa di Michael con Garage.

Ecco le note AI complete su ciò che abbiamo sperimentato ora che il forum è stato distribuito:


Esecuzione di Discourse su Garage self-hosted (S3) dietro un tunnel Cloudflare — note

Garage non è presente nella tabella di compatibilità “Configurare un provider di storage oggetti compatibile con S3”, quindi ecco un dato. Configurazione: Garage v2.3.0, Discourse in due container, Debian 13,
nodo singolo, tunnel Cloudflare invece di un nginx esterno. Premessa: questa è una
piccola distribuzione senza traffico di produzione, quindi trattatela come “funziona” e non come “testata
alla scala di Maker Forums”.

  1. Funziona. Verificato contro i percorsi di codice di Discourse, non tramite CLI: UploadCreator,
    OptimizedImage, ListObjectsV2, HeadObject/GetObject con round trip byte-esatto,
    multipart, delete, remove_upload, più BackupRestore::Backuper che scrive nel bucket
    dei backup e BackupStore#files / #download_file che lo legge. La configurazione del ciclo di vita
    funziona, quindi s3_configure_tombstone_policy ha effettivamente effetto invece di essere
    ignorata silenziosamente. PutBucketCors funziona, quindi CORS manuale va bene.

  2. Devi configurare l’indirizzamento in stile virtual-host, e romperà db:migrate se non lo fai.
    Discourse trasforma l’endpoint http://garage:3900 + bucket “uploads” nell’host
    uploads.garage:3900, e non c’è alcuna opzione path-style in s3_helper.rb o
    site_settings.yml. Sono richieste due parti: root_domain sotto [s3_api] in garage.toml,
    E un nome DNS risolvibile per bucket (un alias di rete Docker per bucket, poiché il DNS
    Docker non ha wildcard). Il sintomo se lo perdi è un errore Aws::Waiters su
    getaddrinfo durante SiteIconManager.ensure_optimized! — sembra un guasto di rete, non
    di storage. Ogni nuovo bucket ha bisogno di un nuovo nome.

  3. Garage non implementa PutObjectAcl / GetObjectAcl, quindi imposta s3_use_acls su false —
    come R2. Due trappole qui. Prima, PutObject con --acl public-read è
    ACCETTATO silenziosamente e l’header è ignorato, quindi i test di caricamento base passano e si rompe solo più tardi
    su una transizione a upload sicuro. Seconda, DISCOURSE_S3_USE_ACLS non è una variabile globale nascosta —
    metterla in app.yml non fa nulla. È risultata true al mio primo avvio nonostante fosse
    nell’ambiente. Deve essere un’impostazione di sito, e deve essere ricontrollata dopo ogni rebuild
    perché nulla ti avvisa.

  4. Se metti un CDN davanti, puntalo all’endpoint WEB di Garage (:3902), non all’API S3
    (:3900). Le letture anonime funzionano solo sull’endpoint web; l’API S3 restituisce correttamente 403
    alle richieste non autenticate, quindi un CDN puntato a :3900 fallisce su ogni immagine mentre le tue
    credenziali sono perfettamente valide. Hai anche bisogno di garage bucket website --allow sul
    bucket uploads, e di un root_domain sotto [s3_web]. Attivalo solo su uploads — il
    bucket dei backup non deve mai essere leggibile anonimamente.

  5. ListObjectVersions restituisce NotImplemented su Garage. Non importa: cercando
    s3_helper.rb e file_store/s3_store.rb per list_object_versions / object_versions
    non si trovano occorrenze. Discourse non usa la versioning degli oggetti S3; la scadenza dei tombstone è
    tramite regole di ciclo di vita più un prefisso.

  6. Testare con aws-cli o mc NON prova la compatibilità. Entrambi usano di default
    l’indirizzamento path-style contro un endpoint personalizzato; Discourse usa solo virtual-host style. Il mio passaggio
    CLI è tornato 15/16 e sembrava un via libera, poi l’installazione reale è fallita
    immediatamente sulla differenza di indirizzamento. Stesso storage, stesse credenziali, stesse
    operazioni. Se stai valutando un backend S3 non provato, fai girare un vero Discourse — una
    istanza single-container usa e getta è sufficiente, e farlo prima che esista contenuto è il punto, poiché S3 → locale è a senso unico.

  7. Specificamente su un tunnel Cloudflare: la sezione external-nginx-for-SSL non si applica
    (TLS termina al bordo, nessun certbot, nessuna porta 80/443 in ingresso), ma la configurazione real-IP outlet
    è ancora essenziale e forse più importante. Usa real_ip_header CF-Connecting-IP
    invece di X-Forwarded-For — quando il tunnel è l’unico percorso di ingresso è un singolo
    valore edge-set inequivocabile. Verificalo pubblicando da un IP pubblico noto e controllando
    cosa ha registrato nginx; senza di esso Discourse registra l’indirizzo Docker del connettore per
    ogni richiesta e limita la velocità di tutto l’Internet come un solo cliente. Ciò che perdi rispetto
    all’approccio external-nginx è la pagina di manutenzione durante i rebuild — cloudflared
    non può servirla.

  8. Minore correzione a qualcosa ampiamente (male)detto, incluso da me: DISCOURSE_S3_CDN_URL
    non è incorporato in modo irreversibile negli URL memorizzati. upload.url memorizza l’URL S3 grezzo con
    l’host interno, ma Discourse sostituisce l’host CDN al momento del rendering tramite
    Discourse.store.cdn_url / UrlHelper.cook_url. Impostarlo in ritardo è recuperabile — il
    costo è rake posts:rebake, perché posts.cooked memorizza in cache l’HTML dal momento della cottura. Impostalo comunque
    prima del primo caricamento; ma non andare nel panico se non l’hai fatto.

  9. Due note operative non correlate a Garage. ./launcher eco la riga docker run completa
    inclusa DISCOURSE_S3_SECRET_ACCESS_KEY in testo piano, quindi i log di bootstrap contengono segreti — vale la pena ruotare le chiavi dopo un’installazione rumorosa. E un Garage single-node
    richiede comunque layout assign + layout apply prima di memorizzare qualcosa, con
    replication_factor = 1 che significa nessuna replica, quindi il tuo lavoro di backup è l’unica
    durabilità che hai.