- Vrealmatic
- Cloudflare
- Bezpečný deploy
Bezpečný deploy na Cloudflare
API token pro jeden účet, mimo kód - krok za krokem pro Next.js i Express, včetně starých chunků po deployi
Návod, podle kterého zvládnete postupovat i bez hlubší znalosti Cloudflare: jak vytvořit token se správnými oprávněními, udržet ho mimo nasazený kód, zamknout deploy na jeden účet, ověřit, že to funguje, a nasadit bez rozbití stránek, které mají návštěvníci otevřené.
Obsah návodu
00 · Přehled
Bezpečný deploy v kostce
Návod nastaví deploy na Cloudflare Workers tak, aby se API token nikdy nedostal do nasazeného kódu, každý deploy šel právě do jednoho účtu a návštěvníkům se po deployi nerozbily otevřené stránky. Každý příkaz jde zkopírovat jedním kliknutím.
Zvolte svou technologii
Většina kroků je stejná pro každý projekt. Kde se Next.js a Express liší, ukazuje návod záložky jako tyto. Volba platí pro celou stránku a zapamatuje se.
- Riziko: build OpenNext zkopíruje všechny hodnoty z
.envdo Workeru, takže token z něj běží v produkci. - Projděte: všechny kapitoly, včetně starých chunků v kapitole 06.
- Statický export (
output: "export") na Workers Static Assets: kapitoly 03 až 05 jako u Workeru a k tomu staré chunky.
- Riziko: Wrangler
.envdo nasazeného bundlu nedává, alewrangler devpředá každou proměnnou z něj vašemu kódu a proměnná s účtem v něm snadno nadělá zmatek. - Projděte: všechny kapitoly kromě starých chunků (ty jen pokud servírujete JS s hashem z frontendového buildu).
- Containers / Docker: jako Worker a navíc
.env*do.dockerignore.
Celé nastavení v kostce
- Jeden token na projekt - token pro jeden účet jen s oprávněními, která projekt používá, omezený na vaši IP adresu
- Zamčený účet -
"account_id"vewrangler.jsonc, takže deploy nemůže skončit v jiném účtu - Token mimo kód - token je v
.env.deploy, který nečte žádný framework aniwrangler dev; nikdy v.env - Načíst jen pro jeden příkaz - npm skripty soubor načtou ve vlastním bashi;
npm run -s wr --nahrazujenpx wrangler - Ověřit a nasadit - kontrola účtu a výstupu buildu, deploy a (Next.js) zachování starých JS chunků, aby otevřené stránky fungovaly dál
Co potřebujete vyřešit?
| Otázka | Kde najdete odpověď |
|---|---|
| Proč je token v .env nebo wrangler login problém? | Proč → |
| Co potřebuji, než začnu? | Než začnete → |
| Jaká oprávnění má token mít? | Vytvoření tokenu → |
| Jak upravit soubory projektu? | Nastavení projektu → |
| Jak ověřím, že token není v buildu? | Ověření → |
| Po deployi otevřené stránky padají na ChunkLoadError. | Staré chunky → |
| Token už máme v .env. Co teď? | Přechod ze starého nastavení → |
| Dostávám 403, okno OAuth nebo „not authenticated“. | Řešení problémů → |
Stav k říjnu 2026: Wrangler 4, @opennextjs/cloudflare 1.x, účtové API tokeny. Nastavení běží v produkci na tomto webu (Next.js na OpenNext, D1, R2, Workers Cache) i na našich Workerech s Expressem. Příkazy potřebují bash: Linux, macOS nebo WSL ve Windows.
01 · Proč
Co je špatně na wrangler login a tokenu v .env
Běžné nastavení, tedy wrangler login nebo token v .env, funguje, ale má slabá místa. Snadno se nasadí do špatného účtu a token se může dostat tam, kam nepatří: do produkčního kódu nebo na dosah vašeho kódu a jeho závislostí.
wrangler login otevře všechny účty
npx wrangler login vás přihlásí přes OAuth jako osobu. Wrangler pak má přístup ke všem účtům, jejichž jste členem: k vlastnímu i ke všem klientským. Stačí jeden příkaz spuštěný ve špatné složce nebo projekt bez pevně daného účtu a deploy, dotaz do D1 nebo smazání bucketu skončí jinde, než má. Token vytvořený pro jeden účet tohle udělat nemůže.
Kam se dostane token z .env
Wrangler si .env načte sám, takže dát token tam vypadá přirozeně. Jenže soubor čtou i další nástroje a co se stane dál, záleží na technologii:
| Kde | Jak se token dostane do nasazeného kódu |
|---|---|
| Build OpenNext | zapíše všechny hodnoty z .env, .env.local, .env.<mode> a .env.<mode>.local do .open-next/cloudflare/next-env.mjs a za běhu je nahraje do process.env |
| Next.js standalone | .next/standalone obsahuje kopii .env |
| Docker | COPY . . bez .env* v .dockerignore zkopíruje soubor do image |
| Prohlížeč | proměnné s prefixem NEXT_PUBLIC_ a hodnoty v next.config → env skončí ve veřejném JavaScriptu |
U OpenNext je tedy token z .env v produkčním Workeru a přes process.env ho přečte váš kód i každá závislost.
Prostý wrangler deploy soubor .env do nasazeného bundlu nedává. Bezpečný tam token přesto není:
| Kde | Co se stane |
|---|---|
wrangler dev | udělá z každé proměnné v .env binding Workeru (když neexistuje .dev.vars). Lokálně pak váš kód i každá závislost přečte env.CLOUDFLARE_API_TOKEN. |
wrangler types | zapíše tyto proměnné do typu Env (worker-configuration.d.ts), takže název tokenu skončí v gitu |
| Vlastní build | dotenv načtený při buildu nebo esbuild define umí hodnoty vložit přímo do bundlu a ten jde do produkce |
| Containers / Docker | COPY . . bez .env* v .dockerignore zkopíruje soubor do image |
| Frontendový build | proměnné s prefixem VITE_ (a podobné) skončí v JavaScriptu, který jde do prohlížeče |
U Workeru s Expressem tedy token z .env v produkci většinou není, ale chybí k tomu jedna změna buildu a na dosah je všemu, co běží pod wrangler dev.
Kdo se dostane k deploy tokenu (přes kód Workeru, jeho prostředí, logy nebo napadenou závislost), může nasazovat, číst databáze a mazat úložiště ve vašem účtu. Token platí, dokud ho v dashboardu nesmažete, i když ho mezitím z .env odstraníte.
02 · Než začnete
Co budete potřebovat
Deset minut a těchto pár věcí. Pokud něco chybí, vyřešte to nejdřív, další kroky na tom stojí.
- Projekt s konfigurací Wrangleru:
wrangler.jsonc,wrangler.jsonnebowrangler.tomlv kořeni projektu. - bash: Linux a macOS ho mají. Ve Windows pracujte ve WSL (Ubuntu), na samotné příkazy stačí i Git Bash.
- Přístup do dashboardu Cloudflare cílového účtu s právem vytvářet API tokeny.
- Projekt v gitu, ať přesně vidíte, co se změnilo.
Jaký projekt máte?
| V projektu vidíte | Typ projektu | Záložka a co projít |
|---|---|---|
@opennextjs/cloudflare v package.json | Next.js na OpenNext | Next.js, všechny kapitoly včetně starých chunků |
wrangler.jsonc s "main", bez Next.js | Worker (Express, Hono…) | Workery, všechny kapitoly, staré chunky jen s frontendovým buildem s hashi |
"assets" bez "main", statický build (Next.js output: "export", Vite) | statický web | Workery. Do výstupu se token dostane jen přes NEXT_PUBLIC_ / VITE_, takže stačí zamčený účet, .env.deploy a vlastní token. Staré chunky platí také (CHUNKS_DIR). |
Dockerfile + containers v konfiguraci | Cloudflare Containers | Workery a navíc .env* do .dockerignore |
| Express na vlastním serveru (bez Wrangleru) | není Worker | server žádný token Cloudflare nepotřebuje, držte ho jen na stroji, ze kterého nasazujete |
03 · Token
Vytvořte token pro jeden projekt
Pro každý projekt vytvořte samostatný token. Když budete mít podezření na únik, smažete jeden token a ostatní projekty běží dál. Cloudflare ukáže hodnotu tokenu jen jednou, takže mějte projekt otevřený a připravený token vložit.
Krok 1: Otevřete formulář tokenu ve správném účtu
V dashboardu se přepněte do účtu projektu a otevřete Manage Account → Account API Tokens → Create Token → Custom token. Účtový token patří účtu a do jiného účtu se nikdy nedostane. Funguje i uživatelský token (My Profile → API Tokens), jen ho musíte na jeden účet omezit sami (krok 3).
Krok 2: Pojmenujte token a přidejte jen oprávnění, která projekt používá
Název: např. my-app deploy. Pak pro každý potřebný řádek klikněte na Add more. Podívejte se na bindingy ve svém wrangler.jsonc: d1_databases znamená D1, r2_buckets R2, kv_namespaces KV.
Workers Scripts pokrývá deploy, secrets, Durable Objects i logy. Pokud deploy později spadne na chybějící oprávnění (Queues, Containers, Images), přidejte jen to jedno.
| Oprávnění (typ → položka → úroveň) | Kdy |
|---|---|
| Account → Workers Scripts → Edit | vždy |
| Account → Account Settings → Read | vždy |
| Account → D1 → Edit | d1_databases v konfiguraci |
| Account → Workers R2 Storage → Edit | r2_buckets (i incremental cache OpenNext) |
| Account → Workers KV Storage → Edit | kv_namespaces |
| Zone → Workers Routes → Edit | jen s routes v konfiguraci, a Zone Resources omezte na tu jednu zónu |
Šablona je pohodlná, ale dává mnohem víc, než deploy potřebuje: kromě Workers Scripts i KV, R2, Tail, údaje o uživateli a Workers Routes na všech vašich zónách. Začněte volbou Custom token a přidejte jen řádky z tabulky výše.
Krok 3: Omezte token na jeden účet
Jen ve formuláři uživatelského tokenu: v sekci Account Resources nechte Include a místo All accounts vyberte účet projektu. Je to nejdůležitější pole celého formuláře. Formulář účtového tokenu ho nemá, protože token je k účtu vázaný.
Krok 4: Povolte token jen z vaší IP adresy
V sekci Client IP Address Filtering nechte Allow a zadejte svou veřejnou adresu. Uniklý token je pak jinde k ničemu. Adresy zjistíte takto:
# your public IPv4 address
curl -4 -s https://ifconfig.me; echo
# your public IPv6 address (no output = you have none, skip it)
curl -6 -s --max-time 5 https://ifconfig.me; echoPokud máte i IPv6, přidejte ji přes Add more (adresu nebo její rozsah /64). Jinak se Wrangler může připojit přes IPv6 a dostane chybu 403. Seznam jde upravit i později, třeba když vám poskytovatel adresu změní.
Krok 5: Nastavte platnost, vytvořte token a zkopírujte ho
TTL je nepovinné; rozumná výchozí volba je rok, pak token přegenerujete. Klikněte na Continue to summary → Create Token a hodnotu zkopírujte. Neposílejte ji chatem ani e-mailem, v další kapitole ji vložíte rovnou do projektu. Zkopírujte si i Account ID: na Account home klikněte na tři tečky vedle názvu účtu a zvolte Copy account ID. Account ID není tajné.
04 · Projekt
Nastavení projektu
Pět drobných úprav v projektu. Všechno jsou soubory, které commitujete, kromě .env.deploy, který zůstává jen ve vašem počítači.
Krok 1: Zapište Account ID do wrangler.jsonc
Přidejte "account_id" hned pod "name". Od teď každý deploy i wrangler příkaz tohoto projektu míří jen do tohoto účtu. Pokud má projekt víc konfigurací Wrangleru (např. samostatný statický Worker), přidejte ho do každé.
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-app",
// Locked to one account: a deploy or any wrangler command cannot land in another account.
// The API token lives in .env.deploy (see package.json scripts "deploy" and "wr").
"account_id": "<ACCOUNT_ID>",
// ... the rest of your config stays as it is
}Krok 2: Vložte token do .env.deploy
Vytvořte soubor v kořeni projektu a vložte do něj token. Next.js, OpenNext i Vite načítají jen .env, .env.local, .env.<mode> a .env.<mode>.local, wrangler dev jen .dev.vars nebo .env. Soubor .env.deploy sám od sebe nečte nic.
# Only for deploys and the wrangler CLI. Next.js, OpenNext and Vite never read this file.
CLOUDFLARE_API_TOKEN="<API_TOKEN>"# only you can read the file
chmod 600 .env.deploy
# must print a .gitignore rule; if it prints nothing, add one
git check-ignore -v .env.deploy || echo '.env*' >> .gitignore# Docker only: keep all env files out of the image
echo '.env*' >> .dockerignoreKrok 3: Odstraňte proměnné Cloudflare ze všech ostatních env souborů
Smažte řádky CLOUDFLARE_API_TOKEN a CLOUDFLARE_ACCOUNT_ID z .env, .env.local, .env.production, .dev.vars a podobných. První příkaz níže nesmí nic vypsat.
# Which env files still contain Cloudflare variables? (prints names, never values)
grep -l 'CLOUDFLARE_' .env .env.* .dev.vars 2>/dev/null | grep -v '^.env.deploy$'
# Show the variable names in .env without their values
sed 's/=.*/=<redacted>/' .envProč i Account ID, když není tajné? U příkazů pro Workery vyhrává account_id ve wrangler.jsonc (ověřeno na Wrangleru 4.98 i 4.149), ale příkazy wrangler pages … dávají přednost proměnné a wrangler dev ji předá vašemu kódu jako binding. Jedno místo pro účet obojímu předejde.
Krok 4: Nechte token načítat npm skripty
Každý skript spustí vlastní bash, načte do něj .env.deploy a provede jeden příkaz. Token ve vašem terminálu nezůstane. V package.json nahraďte odpovídající skripty:
"scripts": {
"dev": "bash -c 'set -a; . ./.env.deploy; set +a; exec next dev \"$@\"' dev",
"cfbuild": "bash -c 'set -a; . ./.env.deploy; set +a; exec opennextjs-cloudflare build'",
"preview": "bash -c 'set -a; . ./.env.deploy; set +a; opennextjs-cloudflare build && exec opennextjs-cloudflare preview'",
"deploy": "bash -c 'set -a; . ./.env.deploy; set +a; opennextjs-cloudflare build && scripts/keep-old-chunks.sh merge && opennextjs-cloudflare deploy && scripts/keep-old-chunks.sh save'",
"wr": "bash -c 'set -a; . ./.env.deploy; set +a; exec wrangler \"$@\"' wr"
}- OpenNext hodnoty z prostředí shellu do buildu nezapisuje, takže načíst token pro
cfbuildadeployje bezpečné. devpotřebuje token jen tehdy, když má některý binding"remote": true(pak čte produkční data). Bez obalu by otevřel okno OAuth.scripts/keep-old-chunks.sh, který voládeploy, je v kapitole 06.
"scripts": {
// your own build step, if the project has one (templates, CSS…); it needs no token
"build": "node scripts/build.mjs",
"dev": "bash -c 'set -a; . ./.env.deploy; set +a; exec wrangler dev \"$@\"' dev",
"start": "npm run dev",
"deploy": "npm run build && bash -c 'set -a; . ./.env.deploy; set +a; exec wrangler deploy'",
"wr": "bash -c 'set -a; . ./.env.deploy; set +a; exec wrangler \"$@\"' wr",
// local only, needs no token
"cf-typegen": "wrangler types"
}- Vlastní build (šablony, CSS, bundle) běží před obalem a bez tokenu. Dostane ho jen
wrangler deploy. devastartpotřebují token jen tehdy, když má binding"remote": true. Obal ho do Workeru nepustí:wrangler devmu předá jen.dev.vars/.env.wrangler typestoken nepotřebuje. Pokud dřívější běh zapsalCLOUDFLARE_*doworker-configuration.d.ts, smažte ty řádky ručně: přegenerování novějším Wranglerem udělá obrovský diff.
# Did wrangler types put Cloudflare variables into the Env type? (must print nothing)
grep -n 'CLOUDFLARE_' worker-configuration.d.tsKrok 5: Místo npx wrangler používejte npm run -s wr --
Vše za -- dostane Wrangler. Nahraďte npx wrangler i v README, dokumentaci a skriptech, ať nikdo nespustí příkaz bez tokenu.
# instead of: npx wrangler <command>
npm run -s wr -- whoami
npm run -s wr -- tail
npm run -s wr -- d1 execute <DB_NAME> --remote --command "SELECT 1"
npm run -s wr -- r2 object get <BUCKET>/<KEY> --remoteProč ne vlastní --env-file Wrangleru? Funguje jen za názvem příkazu (wrangler whoami --env-file=…), před ním Wrangler vypíše jen nápovědu. Obal je jednodušší a stejný pro všechny příkazy.
Tajemství, která aplikace potřebuje za běhu
API klíče, které serverový kód čte za běhu (platby, e-maily, mapy na serveru), do .env také nepatří. V produkci jsou to secrets Workeru. Pozor: secret put vytvoří novou verzi Workeru v produkci.
# Runtime secrets of the app (third-party API keys etc.), never in .env.
# The value is read from .env and piped in, so it never shows up on screen or in the shell history.
grep '^MY_SECRET=' .env | cut -d= -f2- | npm run -s wr -- secret put MY_SECRET
# check (prints names only), then delete the line from .env
npm run -s wr -- secret listOpenNext za běhu zkopíruje secrets Workeru do process.env a mají přednost před hodnotami z buildu. Kód zůstává stejný: process.env.MY_SECRET.
Workery čtou secrets z env v handleru. process.env funguje jen s nodejs_compat a compatibility_date 2025-04-01 nebo novějším. Ověřte, jak je čte váš kód, nepředpokládejte.
// Workers: read secrets from env in the handler
export default {
async fetch(request, env) {
const key = env.MY_SECRET;
// ...
},
};
// Express with nodejs_compat and compatibility_date 2025-04-01 or later:
// bindings and secrets are in process.env as well
const key = process.env.MY_SECRET;Lokální hodnoty pro wrangler dev patří do .dev.vars (nebo .env), produkční do secret put. Tokeny Cloudflare nepatří ani do jednoho.
# Local values for wrangler dev (only app secrets, never Cloudflare tokens).
# With .dev.vars present, wrangler dev ignores .env.
MY_SECRET="local-test-value"05 · Ověření
Kontrola před prvním deployem
Tři kontroly před prvním deployem. Každá trvá pár sekund, a když neprojde, řekne vám přesně, co je špatně.
Krok 1: Wrangler vidí token a správný účet
npm run -s wr -- whoami
# → "You are logged in with an Account API Token" (or "User API Token")
# and the account you expectVidíte jiný účet nebo chybu? Zkontrolujte hodnotu tokenu v .env.deploy a že příkaz spouštíte v kořeni projektu. U uživatelského tokenu se vypíše i Unable to retrieve email… User Details Read: je to jen informace, žádné oprávnění přidávat není třeba.
Krok 2: Bez obalu Wrangler přihlášený není
npx wrangler whoami
# → "You are not authenticated. Please run `wrangler login`."
# That is correct: without the wrapper there is no token. Do NOT run wrangler login.Pokud hlásí přihlášení, je aktivní stará relace OAuth (spusťte npx wrangler logout) nebo je token pořád v .env či ve vašem shellu (otevřete nový terminál a vraťte se ke kroku 3 kapitoly 04).
Krok 3: Výstup buildu neobsahuje token
Sestavte projekt lokálně (nic se nenasadí) a prohledejte výstup. Kontroly vypisují jen názvy, nikdy samotný token.
npm run cfbuild
# OpenNext: no Cloudflare variable in the Worker bundle (must print 0)
grep -c CLOUDFLARE_ .open-next/cloudflare/next-env.mjs
# Any project: no value from .env.deploy anywhere in the build output.
# Prints file names only, never the values. Empty output = OK.
while IFS='=' read -r k v; do v=${v//\"/}; [ -n "$v" ] && [ "${k#\#}" = "$k" ] && \
grep -rlF -- "$v" .open-next .next dist build 2>/dev/null | sed "s|^|$k found in: |"; done < .env.deployNěco nalezeno? Některá proměnná Cloudflare je pořád v .env souboru, který build čte. Odstraňte ji a sestavte znovu.
# Build the bundle exactly as a deploy would, but upload nothing
# (with your own build step: npm run build first)
npm run -s wr -- deploy --dry-run --outdir /tmp/wr-check
# No value from .env.deploy in the bundle. Prints file names only, never the values. Empty output = OK.
while IFS='=' read -r k v; do v=${v//\"/}; [ -n "$v" ] && [ "${k#\#}" = "$k" ] && \
grep -rlF -- "$v" /tmp/wr-check 2>/dev/null | sed "s|^|$k found in: |"; done < .env.deployA lokálně: bindingy, které wrangler dev předává vašemu kódu, nesmí obsahovat žádnou proměnnou Cloudflare.
npm run dev
# The table "Your Worker has access to the following bindings" must not contain CLOUDFLARE_*.
# If it does, the variable is still in .env or .dev.vars.Něco nalezeno v bundlu? Hledejte dotenv nebo define ve svém build skriptu. V bindingách? Proměnná je pořád v .env nebo .dev.vars.
06 · Deploy
Deploy, rollback, CI a staré chunky
Se skripty z kapitoly 04 je deploy jediný příkaz. Kapitola dál popisuje rollback, CI a u Next.js a statických webů i to, jak po deployi udržet funkční stránky, které mají návštěvníci otevřené.
Deploy
npm run deploy
# 1. build 2. add old chunks 3. deploy 4. archive the deployed chunks
# Step 4 runs only when the deploy succeeded.První deploy vypíše no archive yet, to je v pořádku. Od druhého uvidíte added N old files. Jak archiv funguje, je popsané níže.
npm run deploy
# 1. your own build step (if any) 2. wrangler deploy with the token from .env.deployWrangler Worker zabalí až při deployi. Statický web s JS s hashi (export Next.js, Vite) by měl držet i staré chunky, viz níže.
Rollback
Statické soubory jsou součástí každé verze Workeru, takže rollback vrátí i soubory té verze. Nový build není potřeba.
npm run -s wr -- deployments list # recent versions
npm run -s wr -- rollback # back to the previous versionDeploy z CI
V GitHub Actions nebo GitLabu uložte token jako tajnou proměnnou (secret) a předejte ho jen krokům, které ho potřebují. Nikdy před buildem negenerujte .env z tajných proměnných CI, tím byste vrátili původní problém. Runnery hostované GitHubem mění IP adresy, takže filtr IP tam nefunguje: použijte samostatný token pro CI s krátkým TTL, nebo vlastní runner s pevnou adresou.
# GitHub Actions: the token goes only to the steps that need it, never into a .env file
- run: npm ci
- run: npx opennextjs-cloudflare build
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} # only if bindings use "remote": true
- run: scripts/keep-old-chunks.sh merge
env:
OLD_ASSETS_DIR: ${{ runner.temp }}/old-assets # restore it with actions/cache
- run: npx opennextjs-cloudflare deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
- run: scripts/keep-old-chunks.sh save
env:
OLD_ASSETS_DIR: ${{ runner.temp }}/old-assetsArchiv chunků musí přežít mezi běhy, např. přes actions/cache nad OLD_ASSETS_DIR.
# GitHub Actions: the token goes only to the deploy step, never into a .env file
- run: npm ci
- run: npm run build --if-present # your own build step, no token
- run: npx wrangler deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}Staré chunky (Next.js a statické weby)
Každý build Next.js dá souborům JS a CSS nové názvy. Stránky, které mají návštěvníci otevřené nebo v cache prohlížeče, ale chtějí ty staré. Pokud je nový deploy neobsahuje, stránka se rozbije. Řešení: držet archiv starých chunků a přidávat ho ke každému deployi. Worker s Expressem bez frontendu s hashi to nepotřebuje.
- návštěvník má stránku otevřenou a klikne na odkaz (navigace v prohlížeči načítá další chunky staré verze),
- prohlížeč ukáže HTML z cache (na tomto webu až 10 minut),
- edge nebo CDN cache drží HTML přes deploy (Workers Cache s
cross_version_cache).
Návštěvník vidí prázdnou nebo zamrzlou stránku a konzole hlásí ChunkLoadError nebo 404 pro /_next/static/…. Názvy chunků obsahují hash obsahu, takže se staré a nové soubory nikdy nepřepíšou a je bezpečné držet obojí.
Krok 1: Přidejte skript, který drží staré chunky
Uložte ho jako scripts/keep-old-chunks.sh. merge zkopíruje archivované chunky do čerstvého buildu (nový soubor nikdy nepřepíše), save přidá nasazené chunky do archivu. Archiv leží mimo projekt, v ~/next-deployments-old-assets/<složka projektu>, takže ho čistý checkout ani rm -rf .open-next nesmaže.
#!/usr/bin/env bash
# Keeps the JS/CSS chunks of earlier builds available after a deploy.
# merge before the deploy: copy archived chunks into the fresh build (new files are never overwritten)
# save after a successful deploy: add the deployed chunks to the archive
# Archive: $OLD_ASSETS_DIR, default ~/next-deployments-old-assets/<project folder name>
# Chunk folder: $CHUNKS_DIR, default .open-next/assets/_next/static (OpenNext); static export: out/_next/static
set -euo pipefail
BUILD="${CHUNKS_DIR:-.open-next/assets/_next/static}"
ARCHIVE="${OLD_ASSETS_DIR:-$HOME/next-deployments-old-assets/$(basename "$PWD")}/$BUILD"
# Copy files from $1 to $2 that do not exist in $2 yet; the count goes to COPIED.
# Paths keep the leading "./" (build folders may start with "-").
COPIED=0
copy_missing() {
local src=$1 dst=$2 f
COPIED=0
while IFS= read -r -d '' f; do
if [ ! -e "$dst/$f" ]; then
mkdir -p -- "$(dirname -- "$dst/$f")"
cp -p -- "$src/$f" "$dst/$f"
COPIED=$((COPIED + 1))
fi
done < <(cd "$src" && find . -type f -print0)
}
# Delete Windows "Zone.Identifier" files (created when files are copied through Windows Explorer into WSL).
remove_zone_ids() {
local dir n
for dir in "$@"; do
[ -d "$dir" ] || continue
n=$(find "$dir" -type f -name '*:Zone.Identifier' -print -delete | wc -l)
[ "$n" -gt 0 ] && echo "keep-old-chunks: deleted $n Zone.Identifier files in $dir"
done
return 0
}
[ -d "$BUILD" ] || { echo "keep-old-chunks: $BUILD not found, run the build first" >&2; exit 1; }
remove_zone_ids "$ARCHIVE" "$BUILD"
case "${1:-}" in
merge)
if [ -d "$ARCHIVE" ]; then
copy_missing "$ARCHIVE" "$BUILD"
echo "keep-old-chunks: added $COPIED old files from $ARCHIVE"
else
echo "keep-old-chunks: no archive yet ($ARCHIVE), it starts with this deploy"
fi
;;
save)
mkdir -p "$ARCHIVE"
copy_missing "$BUILD" "$ARCHIVE"
echo "keep-old-chunks: archived $COPIED new files to $ARCHIVE"
;;
*)
echo "usage: $0 merge|save" >&2
exit 2
;;
esacchmod +x scripts/keep-old-chunks.shJiné umístění? Nastavte OLD_ASSETS_DIR. Skript z archivu i buildu maže soubory Zone.Identifier z Windows, které vznikají při kopírování přes Průzkumník do WSL.
Krok 2: Zavolejte ho kolem deploye
merge před deployem, save až po úspěšném, aby se do archivu nedostaly soubory, které nikdy nebyly nasazené. Skript deploy pro OpenNext z kapitoly 04 to už dělá. Statický export Next.js jen nastaví CHUNKS_DIR:
# Static Next.js export (output: "export") deployed as Workers Static Assets
"deploy": "next build && CHUNKS_DIR=out/_next/static scripts/keep-old-chunks.sh merge && bash -c 'set -a; . ./.env.deploy; set +a; wrangler deploy' && CHUNKS_DIR=out/_next/static scripts/keep-old-chunks.sh save"Archiv naroste o pár set kilobajtů na deploy. Kdyby byl někdy velký, smažte v něm nejstarší složky buildů (po pár týdnech je už nikdo nepotřebuje).
07 · Přechod
Přechod z tokenu v .env
Přechod z tokenu v .env. Postupujte v tomto pořadí: web poběží dál a starý token přestane platit až ve chvíli, kdy ho už nic nepotřebuje. Začněte, dokud je starý token ještě v .env, první dva kroky ho čtou odtamtud.
Build OpenNext ho zapsal do Workeru, který právě běží. Smažte ho až po novém deployi (krok 6), do té doby platí a jde v produkci přečíst.
Prostý wrangler deploy soubor .env nebalí, takže starý token můžete smazat hned, jak funguje nový. Výjimka: vlastní build s dotenv / define nebo Docker bez .dockerignore. Pak nejdřív nasaďte, stejně jako u Next.js.
Krok 2: Najděte starý token v dashboardu
Účtový token je v Manage Account → Account API Tokens, uživatelský v My Profile → API Tokens. Volání níže vypíše ID tokenu a nastaví mu Last used na teď, takže ho v seznamu poznáte. Čerstvého data se nelekněte.
# Which token is it? Prints only its ID, never the token.
# The call also sets "Last used" of that token in the dashboard to now: that is how you spot it in the list.
T=$(grep '^CLOUDFLARE_API_TOKEN=' .env | cut -d= -f2- | tr -d '"')
# account token (Manage Account → Account API Tokens)
curl -s -H "Authorization: Bearer $T" "https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/tokens/verify" | grep -o '"id":"[^"]*"'
# user token (My Profile → API Tokens)
curl -s -H "Authorization: Bearer $T" "https://api.cloudflare.com/client/v4/user/tokens/verify" | grep -o '"id":"[^"]*"'
unset TKrok 3: Vytvořte nový token
Podle kapitoly 03, jeden na projekt.
Krok 4: Upravte projekt
account_id, .env.deploy s novým tokenem, vyčištěný .env, skripty (kapitola 04).
Krok 5: Ověřte účet a build
Krok 6: Nasaďte
npm run deploy. Worker, který teď běží, už žádný token neobsahuje.
Krok 7: Smažte starý token
V dashboardu token, který jste našli v kroku 2. U Next.js teprve teď, u prostého Workeru klidně už po kroku 5.
Krok 8: Zrušte přístup přes OAuth
Pokud jste někdy použili wrangler login:
npx wrangler logout
# then in the dashboard: My Profile → Access Management → Connected Applications → revoke WranglerOvěřte to příkazem git log --all --oneline -- .env. Pokud něco vypíše, token je v historii repozitáře. Chrání vás smazání tokenu v dashboardu (krok 7), přepis historie je volitelný.
08 · Problémy
Když něco nefunguje
Nejčastější potíže a co s nimi, zhruba v pořadí, v jakém je můžete potkat.
| Co vidíte | Příčina | Co udělat |
|---|---|---|
| Okno OAuth: Wrangler wants to access your account | příkaz běží bez tokenu (přímo npx wrangler …) | klikněte na Cancel a spusťte ho znovu přes npm run -s wr -- |
npm run dev otevře okno OAuth | binding má "remote": true a dev není obalený | obalte dev stejně jako ostatní skripty (kapitola 04) |
| You are not authenticated | v prostředí není token | použijte npm skript; wrangler login nespouštějte |
| Unable to retrieve email… User Details Read | uživatelský token bez tohoto oprávnění | jen informace, nic přidávat netřeba |
| 403 / Authentication error | změnila se vaše IP adresa, připojujete se přes IPv6 nebo chybí oprávnění | zkontrolujte svou IP (krok 4) a seznam IP u tokenu, pak oprávnění |
.env.deploy: No such file or directory | příkaz neběží v kořeni projektu | cd do složky s package.json |
| Wrangler vypíše jen nápovědu | --env-file před názvem příkazu | použijte obal, nebo dejte přepínač za příkaz |
| Build spadne při čtení D1 / R2 | binding má "remote": true a build běží bez tokenu | sestavujte přes npm skript (npm run cfbuild), ne přes npx … |
ChunkLoadError po deployi | deploy neobsahoval staré chunky | zkontrolujte cestu k archivu ve výpisu deploye (staré chunky) |
bash: command not found ve Windows | npm spouští skripty v cmd nebo PowerShellu | pracujte ve WSL (Ubuntu), nebo nastavte npm script-shell na Git Bash |
- Jeden projekt = jeden token, jeden účet v account_id a token v .env.deploy.
- Nikdy token Cloudflare v .env (OpenNext ho zabalí, wrangler dev ho předá vašemu kódu) a nikdy wrangler login.
- Před prvním deployem zkontrolujte výstup buildu. Po přechodu smažte starý token, až ho nic nepotřebuje, u Next.js až po novém deployi.
- Next.js a statické weby: staré chunky _next/static držte v archivu mimo projekt a přidávejte je ke každému deployi.
Zdroje
Oficiální dokumentace a další čtení
Návod vychází z dokumentace Cloudflare a OpenNext a z našeho produkčního nastavení:
- Account API tokensÚčtové tokeny a rozdíly oproti uživatelským.
- Vytvoření API tokenuOprávnění, zdroje, filtr IP a TTL.
- Proměnné prostředí WrangleruCLOUDFLARE_API_TOKEN a další proměnné, které Wrangler čte.
- Konfigurace Wrangleruaccount_id, bindingy a vzdálené bindingy.
- SecretsTajné hodnoty Workeru za běhu, .dev.vars a .env pro lokální vývoj.
- process.env ve WorkerechKdy jsou bindingy a secrets dostupné v process.env.
- OpenNext: proměnné prostředíKteré .env soubory OpenNext čte a jak se dostanou do Workeru.
Související
- Cloudflare wikiAPI tokeny, R2 z příkazové řádky, limity plánů.
- Next.js na Cloudflare (anglicky)Statický build, OpenNext Worker, D1, R2 a incremental cache.
- Express na Cloudflare Workers (anglicky)Express přes httpServerHandler, nodejs_compat a bindingy.
- Cloudflare Workers CacheEdge cache před Workerem, purge a deploy.
Jak citovat tuto publikaci (ČSN ISO 690:2022)NEPOR, Vladimír. Bezpečný deploy na Cloudflare přes API token (Wrangler, OpenNext). Online. Vrealmatic, 2026. Dostupné z: https://vrealmatic.com/cs/cloudflare/deploy. [citováno ].
Nasazujete do více účtů Cloudflare?
Nastavíme tokeny, deploy i celý stack Cloudflare tak, aby nic tajného neskončilo v produkčním kódu.