Provoz Strapi v produkci se dá shrnout do šesti rozhodnutí, která uděláš jednou a zapíšeš si je: sada tajných klíčů v .env, které se po spuštění už nikdy nemění; databáze, kterou umíš zálohovat (SQLite pro jeden menší web, PostgreSQL pro všechno, kde jsou redaktoři a provoz); místo pro nahrané soubory, které přežije nový build; administrace sestavená s NODE_ENV=production; veřejné url, které odpovídá tomu, co obsluhuje reverzní proxy; a postup upgradu, který začíná zálohou. Na pohodlný build administrace potřebuje Strapi zhruba 2 GB paměti, na samotné obsluhování požadavků pak mnohem méně. Když těchhle šest věcí uděláš správně, je Strapi tichý proces Node na portu 1337. Když jednu pokazíš, zjistíš to v den, kdy se redaktor přihlásí a všechny API tokeny přestanou fungovat.
Tento návod popisuje Strapi 5, aktuální hlavní verzi, a upozorňuje, kde se liší Strapi 4. Názvy souborů jsou uvedené jako .js; projekt v TypeScriptu má tytéž soubory jako .ts.
Jak je aplikační server se Strapi poskládaný#
Strapi je aplikace v Node.js ze dvou polovin, které běží v jednom procesu. První je API pro obsah: REST (a GraphQL, pokud přidáš plugin) pod /api, vygenerované z typů obsahu, které sis nadefinoval. Druhá je administrace, aplikace v Reactu na adrese /admin, ve které redaktoři píšou obsah a ve které ty při vývoji vytváříš typy obsahu.
Tohle rozdělení vysvětluje nejpřekvapivější pravidlo produkčního Strapi: Content-Type Builder funguje jen ve vývojovém režimu. strapi develop sleduje projekt a při změně modelu se restartuje; strapi start to nedělá a builder je jen pro čtení. Typy obsahu jsou kód - JSON schémata v src/api a src/components - a patří do Gitu. Měníš je na vývojové kopii, commitneš a nasadíš, přesně jako migraci databáze v jakémkoli jiném frameworku.
Při startu Strapi porovná tato schémata s databází a srovná tabulky podle nich. Je to pohodlné, a zároveň je to věc, na kterou je třeba dávat pozor: přejmenované pole je pro databázi jedno smazané pole a jedno nové a data ze starého sloupce za novým názvem nepřejdou. Pole přejmenovávej nejdřív na kopii produkčních dat, nikdy na živém webu.
Tři příkazy, které budeš používat; všechny jsou definované v souboru package.json, se kterým se nový projekt vygeneruje:
| Příkaz | Co dělá |
|---|---|
npm run develop | Vývojový režim, automatický restart, Content-Type Builder zapnutý |
npm run build | Sestaví administraci (a zkompiluje TypeScript) |
npm run start | Produkční režim, bez automatického restartu, bez builderu |
Proměnné prostředí a tajné klíče#
Nový projekt dostane soubor .env s těmito položkami, z nichž každou vyplní generátor projektu náhodnou hodnotou. V produkci musí být nastavená každá z nich, jedinečná pro dané prostředí a od dne spuštění neměnná.
| Proměnná | Kdo ji čte | Co se rozbije, když se změní |
|---|---|---|
APP_KEYS | config/server.js | Podepsané session cookies přestanou platit |
API_TOKEN_SALT | config/admin.js | Přestanou fungovat všechny API tokeny |
ADMIN_JWT_SECRET | config/admin.js | Všichni administrátoři jsou odhlášeni |
TRANSFER_TOKEN_SALT | config/admin.js | Přestanou fungovat transfer tokeny |
JWT_SECRET | config/plugins.js | Přihlášení uživatelů (Users and Permissions) vyprší |
APP_KEYS je seznam oddělený čárkami, ne jedna hodnota. Strapi ho čte pomocí env.array('APP_KEYS') a klíči podepisuje cookies; víc klíčů umožňuje jejich rotaci. API_TOKEN_SALT slouží k hashování API tokenů před uložením, a proto jeho změna potichu zneplatní každý token, který drží tvůj frontend, build pipeline nebo mobilní aplikace. JWT_SECRET patří pluginu Users and Permissions - tomu, který vydává tokeny lidem registrovaným na tvém webu, na rozdíl od redaktorů v administraci. Novější projekty na Strapi 5 generují i ENCRYPTION_KEY pro šifrovaná tajemství administrace; pokud ho tvůj .env obsahuje, zacházej s ním stejně.
Zbytek souboru jsou běžná nastavení za běhu:
HOST=0.0.0.0PORT=1337NODE_ENV=productionAPP_KEYS=key1base64==,key2base64==,key3base64==,key4base64==API_TOKEN_SALT=replace-with-random-base64ADMIN_JWT_SECRET=replace-with-random-base64TRANSFER_TOKEN_SALT=replace-with-random-base64JWT_SECRET=replace-with-random-base64STRAPI_TELEMETRY_DISABLED=truePro vygenerování hodnoty stačí jakýkoli zdroj 16 a více náhodných bajtů zakódovaných v base64:
$ openssl rand -base64 32$ node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"Když APP_KEYS chybí, Strapi odmítne nastartovat s chybou middlewaru strapi::session, která říká, že klíče aplikace jsou povinné. To je dobré selhání: hlasité, při startu a zřejmé. Špatná selhání jsou ta tichá popsaná výše, ke kterým dojde, když někdo na běžícím webu přegeneruje klíče. Článek proměnné prostředí a tajné klíče popisuje obecnou disciplínu, jak je držet mimo kód a mimo logy.
SQLite nebo PostgreSQL#
Strapi podporuje SQLite, PostgreSQL a MySQL; volí se proměnnou DATABASE_CLIENT a nastavuje v souboru config/database.js. Vygenerovaný soubor čte všechna nastavení připojení z prostředí, takže přechod je jen otázkou proměnných a instalace správného ovladače.
| Proměnná | K čemu slouží | Výchozí hodnota ve vygenerované konfiguraci |
|---|---|---|
DATABASE_CLIENT | sqlite, postgres nebo mysql | sqlite |
DATABASE_FILENAME | Cesta k souboru SQLite | .tmp/data.db |
DATABASE_HOST | Adresa serveru | localhost |
DATABASE_PORT | Port serveru | 5432 pro PostgreSQL |
DATABASE_NAME | Název databáze | strapi |
DATABASE_USERNAME | Uživatelské jméno | strapi |
DATABASE_PASSWORD | Heslo | strapi |
DATABASE_SSL | TLS k databázi | false |
DATABASE_SCHEMA | Schéma v PostgreSQL | public |
DATABASE_POOL_MIN / MAX | Pool připojení | 2 / 10 |
SQLite je jeden soubor a databáze běží přímo v procesu. Pro marketingový web, portfolio nebo CMS pro dokumentaci s jedním či dvěma redaktory a frontendem, který se sestavuje staticky nebo se cachuje, úplně stačí: čtení je rychlé, nejde se přes síť a nic dalšího se nemusí spouštět ani platit. Její limity jsou zápisy a kopírování. Zápisy se řadí za sebe, takže vytížená administrace spolu s importem spouštěným webhookem bude čekat ve frontě. A soubor je živý: kopie data.db pořízená ve chvíli, kdy Strapi zapisuje, se nemusí dát otevřít.
Všimni si výchozí cesty. .tmp/data.db leží ve složce, jejíž název přímo svádí ke smazání, takže na dlouhodobě běžícím serveru ji buď vědomě nech být, nebo databázi přesuň pomocí DATABASE_FILENAME=data/strapi.db a ověř, že složka existuje.
PostgreSQL je správná volba, jakmile se objeví cokoli z tohoto: několik redaktorů pracujících současně, veřejné API se skutečným provozem, obsah importovaný skripty nebo potřeba konzistentních záloh přes pg_dump, zatímco web běží dál. V projektu k tomu potřebuješ balíček pg:
$ npm install pgDATABASE_CLIENT=postgresDATABASE_HOST=db.example.netDATABASE_PORT=5432DATABASE_NAME=strapiDATABASE_USERNAME=strapiDATABASE_PASSWORD=long-random-passwordDATABASE_SSL=falsePokud dáváš přednost jednomu připojovacímu řetězci, čte se i DATABASE_URL. DATABASE_SSL=true nastav, když se k databázi připojuješ přes internet, a ne přes privátní síť; článek PostgreSQL sslmode vysvětluje, co která úroveň skutečně ověřuje. Výchozí pool deseti připojení jednomu procesu Strapi stačí; pokud jich běží víc, sečti jejich pooly a porovnej je s limitem připojení databáze, jak vysvětluje článek pooly připojení a limity.
Přesun existujícího webu ze SQLite na PostgreSQL se dělá vlastním exportem a importem Strapi, ne převodem souboru: exportuj z instance se SQLite, nasměruj proměnné na prázdnou databázi PostgreSQL, jednou spusť Strapi, aby vytvořil tabulky, zastav ho a pak importuj. Příkazy najdeš níže v části o zálohách.
Nahrané soubory: lokální disk, nebo bucket S3#
Ve výchozím stavu ukládá plugin Upload soubory do public/uploads a Strapi je obsluhuje sám. Na jednom serveru s trvalým diskem to funguje a přesně tak startuje Strapi instalovaný jedním kliknutím. K objektovému úložišti tě dotlačí tři věci: disk, který se plní obrázky a vygenerovanými náhledy, proces nasazení, který nahrazuje složku projektu, a snaha obsluhovat média tak, aby každý požadavek nemusel projít přes Node.
Oficiální poskytovatel S3 pro Strapi je @strapi/provider-upload-aws-s3. Navzdory názvu funguje s jakoukoli službou kompatibilní s S3, pokud mu zadáš endpoint a u většiny služeb mimo AWS i adresování ve stylu path-style.
$ npm install @strapi/provider-upload-aws-s3module.exports = ({ env }) => ({ upload: { config: { provider: 'aws-s3', providerOptions: { baseUrl: env('S3_PUBLIC_URL'), s3Options: { credentials: { accessKeyId: env('S3_ACCESS_KEY_ID'), secretAccessKey: env('S3_ACCESS_SECRET'), }, region: env('S3_REGION'), endpoint: env('S3_ENDPOINT'), forcePathStyle: true, params: { Bucket: env('S3_BUCKET'), }, }, }, actionOptions: { upload: {}, uploadStream: {}, delete: {}, }, }, },});Názvy proměnných za env( si volíš sám; pevná je jen struktura. baseUrl je veřejná adresa, ze které se soubory obsluhují, a může se lišit od endpointu API, pokud před bucketem stojí CDN nebo proxy. forcePathStyle: true zajistí, že požadavky jdou na endpoint/bucket/key místo bucket.endpoint/key - článek path-style a virtual-hosted v S3 vysvětluje, proč to většina samostatně hostovaných úložišť potřebuje.
Krok, který vynechá skoro každý, je Content Security Policy administrace. Middleware strapi::security povoluje obrázky jen z vlastního původu, takže po změně poskytovatele se soubory nahrají, ale náhledy v Media Library jsou rozbité. Přidej hostitele svého bucketu do img-src a media-src v souboru config/middlewares.js:
module.exports = [ 'strapi::logger', 'strapi::errors', { name: 'strapi::security', config: { contentSecurityPolicy: { useDefaults: true, directives: { 'connect-src': ["'self'", 'https:'], 'img-src': ["'self'", 'data:', 'blob:', 'market-assets.strapi.io', 'files.example.com'], 'media-src': ["'self'", 'data:', 'blob:', 'market-assets.strapi.io', 'files.example.com'], upgradeInsecureRequests: null, }, }, }, }, 'strapi::cors', 'strapi::poweredBy', 'strapi::query', 'strapi::body', 'strapi::session', 'strapi::favicon', 'strapi::public',];Změna poskytovatele nepřesune existující soubory. Média nahraná před změnou dál ukazují na /uploads/... na lokálním disku; buď ty soubory nech na místě, nebo naplánuj přesun jako export, změnu poskytovatele a import.
Build administrace a paměť#
npm run build zkompiluje administraci do statických souborů. Spouští se jednou na nasazení, ne na každý požadavek, ale je to paměťově nejnáročnější věc, kterou Strapi dělá: sestavení aplikace v Reactu s administračním kódem všech pluginů může krátce potřebovat výrazně přes gigabajt, zatímco běžící server se potom často drží na pár stovkách megabajtů. Dokumentace Strapi k nasazení uvádí jako minimum 2 GB RAM.
Tři pravidla udrží build mimo potíže:
- Builduj s nastaveným
NODE_ENV=production, aby byla administrace minifikovaná a sestavená pro produkční konfiguraci. - Builduj znovu po všem, co mění administraci: nový plugin, upgrade Strapi, změna
config/admin.js, změna cesty k administraci nebo veřejného URL. - Když build spadne s chybou haldy JavaScriptu, zvyš limit Node jen pro tento příkaz pomocí
NODE_OPTIONS=--max-old-space-size=1536(pod velikostí paměti serveru) a přečti si limity paměti v Node, abys věděl, proč výchozí hodnota není RAM tvého tarifu.
Na serveru s pevným limitem paměti se build, který ho překročí, nezpomalí a nevzpamatuje se; proces je ukončen. Příznakem je build, který se zastaví v půlce bez vlastní chybové hlášky. Tohle se řeší větším tarifem pro build nebo výše uvedeným příznakem haldy, ne opakováním.
Veřejné URL, cesta k administraci a reverzní proxy#
Strapi naslouchá na HOST a PORT - ve výchozím stavu 0.0.0.0:1337 - a počítá s tím, že před ním stojí reverzní proxy kvůli TLS a doméně. Dvě nastavení v souboru config/server.js zajistí, že se tam bude chovat správně:
module.exports = ({ env }) => ({ host: env('HOST', '0.0.0.0'), port: env.int('PORT', 1337), url: env('PUBLIC_URL', 'https://cms.example.com'), app: { keys: env.array('APP_KEYS'), },});url je veřejná adresa webu včetně schématu. Strapi z ní generuje absolutní odkazy - vlastní adresu administrace, URL souborů z lokálního poskytovatele uploadů, odkazy v e-mailech pro obnovu hesla - takže když ji nenastavíš, vzniknou odkazy http://0.0.0.0:1337/..., které fungují jen na samotném serveru. Pokud Strapi obsluhuješ pod podcestou, třeba https://example.com/cms, uveď cestu v url a administraci znovu sestav.
Druhé nastavení je důvěra k proxy. Za proxy vidí Strapi každý požadavek jako obyčejné HTTP z adresy proxy, dokud mu neřekneš, aby důvěřoval hlavičkám X-Forwarded-For a X-Forwarded-Proto. Volba se jmenuje proxy v souboru config/server.js; její tvar se mezi Strapi 4 (logická hodnota) a Strapi 5 (objekt se samostatnými klíči) změnil, proto se podívej na stránku konfigurace serveru pro svou verzi a nekopíruj starý úryvek. Bez ní je klasickou chybou Cannot send secure cookie over unencrypted connection, když se proces přihlášení pokusí nastavit zabezpečenou cookie.
Administrace je ve výchozím stavu na cestě /admin a její cesta se nastavuje v souboru config/admin.js. Přesunutí ji nezabezpečí - API odpovídá tak jako tak - ale ubere to šum od skenerů. Článek co dělá reverzní proxy rozebírá hlavičky podrobně, a pokud před Strapi provozuješ vlastní nginx, v návodu na reverzní proxy s nginx je funkční blok. Pamatuj, že client_max_body_size má v nginx výchozí hodnotu 1m, což zablokuje každý upload větší než jeden megabajt odpovědí 413 dřív, než ho Strapi vůbec uvidí.
Strapi poskytuje /_health, který odpoví prázdnou odpovědí 204, když server běží - hodí se pro monitoring dostupnosti, který se nemá přihlašovat ani volat API závislé na databázi.
Zálohy a obnova#
Vrstvy jsou dvě a chceš obě.
První je databáze plus nahrané soubory, zkopírované jako soubory. S PostgreSQL pořídí pg_dump konzistentní dump, zatímco Strapi dál běží - článek pg_dump a pg_restore probírá formáty i obnovu. U SQLite se bezpečná kopie souboru pořizuje při zastaveném Strapi, nebo nástrojem, který používá backup API samotné SQLite; obyčejná kopie souboru uprostřed zápisu je loterie. Uploady v public/uploads jsou obyčejné soubory. Spolu s kódem projektu a tvým .env tvoří tyto tři části úplnou obnovu.
Druhá vrstva jsou vlastní příkazy Strapi pro přenos dat, které vytvoří přenositelný archiv nezávislý na databázovém stroji:
$ npm run strapi export -- --no-encrypt -f strapi-backup$ npm run strapi import -- -f strapi-backup.tar.gzBez --no-encrypt se archiv zašifruje klíčem, na který se tě příkaz zeptá, a dostane příponu .tar.gz.enc. Archiv obsahuje obsah, nahrané soubory a konfiguraci projektu. Neobsahuje administrátorské účty ani API tokeny, takže nenahrazuje zálohu databáze - je to nástroj pro přechod mezi SQLite a PostgreSQL nebo mezi servery. Import před zápisem smaže existující obsah v cílové instanci, takže ho nikdy nenasměruj na špatnou. strapi transfer dělá totéž naživo mezi dvěma běžícími instancemi Strapi pomocí transfer tokenu, a právě ten chrání TRANSFER_TOKEN_SALT.
Ať zvolíš cokoli, aspoň jednou zálohu někde obnov. Článek zálohy, které se opravdu dají obnovit vysvětluje, proč je záloha, kterou nikdo neobnovil, jen hypotéza.
Bezpečný upgrade Strapi#
Strapi vydává nové verze často a administrace se při každém upgradu sestavuje znovu, takže upgrady si zaslouží zavedený postup, ne npm update. Strapi 5 obsahuje nástroj pro upgrade, který zvýší verze balíčků a spustí transformace kódu:
$ npx @strapi/upgrade patch --dry$ npx @strapi/upgrade minor$ npx @strapi/upgrade majorpatch a minor zůstávají v rámci aktuální hlavní verze; major je cesta ze Strapi 4 na 5 a je to migrační projekt, ne aktualizace - mění se pluginy, vlastní kód i databáze. --dry ukáže, co by se stalo, aniž by cokoli zapsal.
Postup, který funguje:
- Zazálohuj databázi a nahrané soubory a archiv měj jinde než na tomto serveru.
- Proveď upgrade na vývojové kopii s čerstvou kopií produkčních dat.
- Spusť
npm run build, nastartuj aplikaci a proklikej administraci i API, které používá tvůj frontend. - Commitni výsledek včetně lock souboru a nasaď přesně tento commit.
- Na serveru znovu sestav administraci a spusť ji; sleduj log prvního startu, protože právě tehdy proběhnou změny schématu databáze.
Zkontroluj i verzi Node.js. Každé vydání Strapi podporuje určitý rozsah sudých LTS verzí Node; běh na liché verzi nebo na verzi, jejíž podpora skončila, je častou příčinou chyb instalace po upgradu.
Strapi na RE:NODE#
Na RE:NODE je Strapi aplikace na jedno kliknutí na stránce hostingu aplikací. Instaluje a sestavuje se při prvním startu serveru, data jsou v SQLite na serveru, takže první věc, kterou uděláš, je otevřít /admin a vytvořit si administrátorský účet. Tarify začínají na 2 GB paměti, což odpovídá tomu, co build administrace potřebuje. Soubor .env je ve složce projektu a dá se upravit ve správci souborů nebo přes SFTP; než adresu komukoli dáš, ověř, že každý tajný klíč z tabulky výše obsahuje dlouhou náhodnou hodnotu.
Panel pokrývá provozní části, které tento návod popisuje. Nasměruj A záznam na adresu zobrazenou u proxy slotu a certifikát se vystaví a obnovuje automaticky, přičemž skutečná IP klienta přichází v hlavičce X-Forwarded-For. Sloty pro zálohy jsou v každém tarifu, zálohy se spouštějí ručně nebo přes záložku Schedules a ukládají se mimo stroj - viz zálohy v návodech. Protože SQLite je živý soubor, naplánuj zálohy na klidnou hodinu nebo nejdřív zastav server. Až ti SQLite přestane stačit, server PostgreSQL ti dá hodnoty DATABASE_* k vložení a tarif objektového úložiště S3 endpoint, klíče a první bucket pro poskytovatele uploadů, s adresováním path-style a libovolným názvem regionu.
Při dosažení limitu paměti se server zastaví a čistě restartuje, místo aby swapoval - to je přesně příznak ukončeného buildu popsaný výše: když npm run build potichu skončí, je to tím.
Řešení problémů#
Přihlášení do administrace funguje, ale po nasazení jsou všichni odhlášeni. Změnil se ADMIN_JWT_SECRET, obvykle proto, že se vygeneroval nový .env. Obnov původní hodnotu.
Po migraci vrací každý API token `401`. API_TOKEN_SALT se liší od toho, se kterým byly tokeny vytvořeny. Obnov ho, nebo vytvoř nové tokeny a aktualizuj všechny klienty.
Náhledy v Media Library jsou rozbité, ale soubory se nahrávají. Hostitel bucketu chybí v img-src v souboru config/middlewares.js.
Odkazy v e-mailech a URL médií ukazují na `0.0.0.0:1337`. V souboru config/server.js není nastavené url. Nastav ho a administraci znovu sestav.
Administrace po upgradu ukazuje starou verzi. Administrace nebyla znovu sestavena. Spusť npm run build a restartuj.
Uploady nad 1 MB selhávají s `413`. Je to limit velikosti těla požadavku na reverzní proxy, ne Strapi.
Typy obsahu nejde v administraci upravovat. Jsi v produkčním režimu, a tak je to správně. Uprav je ve vývojovém režimu a nasaď.
FAQ#
Stačí SQLite pro Strapi v produkci?
Pro menší web s jedním nebo dvěma redaktory a frontendem, který se cachuje nebo sestavuje staticky, ano. Hůř zvládá mnoho souběžných zápisů a vyžaduje opatrnost při zálohování, takže na PostgreSQL přejdi, jakmile začne upravovat obsah několik lidí najednou nebo API dostává skutečný provoz.
Můžu APP_KEYS nebo jiné tajné klíče později změnit?
Můžeš, ale každá změna něco stojí: podle toho, o který klíč jde, se odhlásí administrátoři, přestanou platit API tokeny nebo skončí uživatelské relace. Rotuj uvážlivě, jeden klíč po druhém, a lidi, kteří tokeny drží, předem upozorni.
Musím po změně .env znovu buildovat?
U přihlašovacích údajů k databázi a tajných klíčů ne - čtou se při startu serveru, takže stačí restart. Nový build je potřeba po změně veřejného URL, cesty k administraci, pluginů nebo verze Strapi.
Proč na produkčním serveru nejde vytvářet typy obsahu?
Strapi mimo vývojový režim Content-Type Builder záměrně vypíná. Modely jsou kód a jejich změna na živém serveru by změnila schéma databáze bez jakéhokoli záznamu ve správě verzí.
Zálohuje strapi export i administrátorské účty?
Ne. Administrátorské účty a API tokeny do archivu nepatří. Měj i zálohu na úrovni databáze a export ber jako nástroj pro migraci a přenos.


