RE:NODE

Startovací šablony: první aplikace na novém serveru za 5 minut

Text: Tým RE:NODE
17 min čtení


Nejrychlejší cesta k běžící aplikaci na novém serveru nevede přes psaní aplikace. Vede přes malý repozitář, který už splňuje čtyři věci, na kterých hostovaný server trvá - poslouchá na 0.0.0.0 na přidělený port, má start skript nebo vstupní soubor, který runtime najde, připíná verzi runtime, kterou server nabízí, a drží tajné údaje mimo Git - a ten pak po jednom commitu předěláš na svou aplikaci. Vytvoř repozitář ze šablony, nasměruj na něj server, stiskni deploy a první start ukáže funkční stránku místo stack trace. Všechno další je běžný vývoj: pushneš, server si stáhne změny a restartuje se.

Tento článek popisuje, co je startovací šablona a v čem se liší od zástupné stránky, kterou ukazuje nový server, pravidla, kterými se řídí každý starter a proč, postup krok za krokem od prázdného serveru po živou aplikaci, co je uvnitř každého ze šesti starterů, které udržujeme (Next.js, Express, bot pro Discord, bot pro Telegram, FastAPI a statický web), jak je upravovat, aby se nerozbil deploy, a jak nastavit deploy při každém pushi. Většina platí na jakémkoli hostingu, který nasazuje z Gitu; části specifické pro RE:NODE jsou jako takové označeny.

Šablona, zástupná stránka, aplikace na jedno kliknutí: tři různé věci#

Slovem „starter“ lidé označují několik věcí a jejich pletení způsobuje většinu zmatku hned první den.

Šablonový repozitář na GitHubu je normální repozitář s jedním zaškrtnutým políčkem v nastavení. Místo forku stiskneš Use this template a GitHub ve tvém účtu vytvoří zbrusu nový repozitář se stejnými soubory a čistou historií. Žádná vazba na originál, žádný upstream, který bys musel synchronizovat, a tvé commity nikdo jiný nevidí. Je tvůj od první vteřiny. To je správný tvar pro starter: do šablony nepřispíváš, bereš ji jako kostru.

Zástupná stránka je to, co ukazuje nový prázdný runtime server, než něco nasadíš. Na RE:NODE se u každé runtime řady kromě Node.js na jeho adrese zobrazí malá funkční stránka, dokud nenasadíš kód, a nikdy nepřepíše tvé soubory. Existuje proto, aby první start čerstvého serveru řekl „tady je, co dělat dál“, místo aby spadl s Cannot find module './index.js'. Není to aplikace, na které by se stavělo - nasazením tvého repozitáře zmizí.

Aplikace na jedno kliknutí je hotový produkt, který se nainstaluje za tebe: WordPress na řadě pro web, Ghost a Strapi na řadě pro aplikace. Konfiguruješ je, nepíšeš je. Pokud chceš blog, je to kratší cesta, a lepším dalším čtením je průvodce Ghostem nebo průvodce Strapi.

Startovací šablona stojí mezi tím: skutečný kód, dost malý na to, aby se dal přečíst za pět minut, a už tvarovaný pro server, na který půjde.

Čtyři pravidla, kterými se řídí každý starter#

Hostovaný aplikační server není tvůj notebook. Spouští jeden proces v kontejneru, tomu procesu dává přesně jeden veřejný port a spouští ho pokaždé stejným způsobem. Téměř každý nezdařený první deploy porušuje jedno z následujících pravidel, a proto je na nich postaven každý starter.

PravidloJak vypadáCo se bez něj rozbije
Poslouchat na 0.0.0.0 na přiděleném portuSERVER_PORT z prostředíAplikace běží, nikdo se k ní nedostane
Start, který runtime najdeskript start nebo app.pyPád při startu, není co spustit
Připnutá verze runtime.nvmrc, .python-versionLokálně funguje, na serveru ne
Tajné údaje mimo Git.env v .gitignoreTokeny uniknou v repozitáři

Port. Na panelu postaveném na Pterodactylu se port, který tvůj server vlastní, předává procesu jako proměnná prostředí SERVER_PORT. Naše starter šablony pro Node.js a Python se navíc vrací k PORT, který používá spousta platforem, a pak k lokálnímu výchozímu portu, takže stejný soubor poběží i na tvém počítači. Na adrese záleží stejně jako na portu: aplikace, která poslouchá na localhost nebo 127.0.0.1, odpovídá jen uvnitř vlastního kontejneru. V konzoli vypadá zdravě a z internetu je nedostupná. 0.0.0.0 znamená všechna rozhraní a je to jediná adresa, která funguje.

Start. Runtime musí vědět, co spustit. U Node.js je to skript start v package.json. U Pythonu je to soubor uvedený na kartě Startup, ve výchozím stavu app.py, spuštěný po instalaci requirements.txt. Webhostingový server nepotřebuje ani jedno - jeho vlastní webový server servíruje index.html z kořenového adresáře webu.

Verze. .nvmrc a .python-version říkají, pro kterou hlavní verzi byl kód napsán. Server ale stejně běží na té verzi, kterou vybereš v Runtime version na kartě GitHub, takže soubor je připomínka a kontrola, ne přepínač - jenže pre-flight kontrola ho čte a řekne ti, když se obě verze rozcházejí, což se hodně vyplatí ve chvíli, kdy Next.js přestane podporovat verzi, kterou sis náhodou vybral.

Tajné údaje. Každý starter obsahuje .env.example s názvy nastavení a falešnými hodnotami a .gitignore, který skutečný .env drží mimo repozitář. Skutečné hodnoty vyplníš na serveru. Víc o tom, proč a jak, v článku proměnné prostředí a tajné údaje.

Šest starterů a co spouštějí#

Udržujeme šest starter repozitářů, každý postavený a otestovaný proti pre-flight kontrole panelu, takže repozitář z něj vytvořený nehlásí nic k opravě. Nabízejí se jen na serverech, jejichž runtime odpovídá.

StarterPro jaký serverCo dostaneš
Next.jsNode.js, Node 22Web v App Routeru s health routou
Express APINode.js, Node 22JSON API: /, /health, /echo
Discord botNode.js, Node 22Bot v discord.js s /ping
Telegram botPython, 3.12Echo bot na long pollingu
FastAPIPython, 3.12API s dokumentací na /docs
Statický webWebhostingHTML a CSS, nic se nebuilduje

Pro Bun, Deno, Go, Javu, Rust, .NET ani Laravel zatím starter není. Node startery čtou .env voláním jen pro Node a připínají verzi Node, kterou Bun nemusí respektovat, a raději nenabídneme nic než šablonu, kterou jsme neověřili. Poslední sekce popisuje, jak tyto runtime spustit z prázdného repozitáře.

Od prázdného serveru k běžící aplikaci, krok za krokem#

Tohle je celá cesta pro starter Express na serveru s Node.js. Ostatní startery se liší jen serverem, který objednáš, a nastavením, které vyplníš.

  1. Objednej server, který kód spustí - pro Express plán Node.js z hostingu aplikací. Vytvoří se po zaplacení, obvykle do minuty.
  2. Otevři na serveru kartu GitHub a stiskni Connect GitHub. Tím se na tvůj účet nainstaluje GitHub App RE:NODE a ty vybereš, které repozitáře smí vidět. App používá krátkodobé tokeny, takže fungují i soukromé repozitáře.
  3. V sekci Start from a template stiskni u Express API Use template. Otevře se vlastní stránka GitHubu „create a repository from a template“ s navrženým názvem. Vyber vlastníka, zvol veřejný nebo soukromý a vytvoř ho. Panel ve tvém účtu nevytváří nic sám - dělá to GitHub, kde už jsi přihlášený.
  4. Vrať se na kartu panelu. Seznam repozitářů se obnoví, když karta znovu získá fokus. Pokud jsi s App sdílel jen vybrané repozitáře, nejdřív přidej ten nový v Manage repository access.
  5. Vyber repozitář, produkční větev nech na main a zvol Runtime version - Node 22 pro každý Node starter.
  6. Stiskni Deploy. Panel si vyžádá potvrzení, protože tím se server přeinstaluje z repozitáře. Na novém serveru nemáš co ztratit.
  7. Spusť server. Konzole ukáže instalaci závislostí a pak Listening on 0.0.0.0: a tvůj port.
  8. Otevři v prohlížeči adresu a port serveru. Dostaneš malou JSON odpověď se zprávou a názvem aplikace.

To je těch pět minut. Nejdéle obvykle trvá krok 3, tedy rozhodnutí, jak repozitář pojmenovat.

Use templatevýběr a deploypřeinstalace0.0.0.0:SERVER_PORTkaždý pushStartovací šablonana GitHubuTvůj repozitářvytvořený z níKarta GitHubvětev, runtimeAplikační serverinstalace a startProhlížečadresa a port
Od šablony k běžící aplikaci

Pokud bys raději použil doménu než adresu a port, zařídí to proxy slot v plánech pro aplikace: nasměruj A záznam na zobrazenou adresu a certifikát se vystaví a obnovuje automaticky. Tvá aplikace dál poslouchá na vlastním portu; proxy stojí před ní a skutečná IP klienta přijde v X-Forwarded-For.

Co je uvnitř každého starteru#

Každý je záměrně malý. Smysl je v tom, že si můžeš přečíst všechno, než cokoli změníš.

Express API

server.js načte volitelný .env, nastaví tři routy a začne poslouchat. Důležitých je posledních pár řádků:

server.js
const port = Number(process.env.SERVER_PORT || process.env.PORT || 3000);app.listen(port, '0.0.0.0', () => {    console.log(`Listening on 0.0.0.0:${port}`);});

.env se čte vestavěným process.loadEnvFile() z Node 22, takže tu není závislost na dotenv. npm run start spustí node server.js; nic se nebuilduje. Co přijde po starteru - ošetření chyb, logování, správný provoz - najdeš v článku nasazení Express API do produkce.

Next.js

Starter pro Next.js je web v App Routeru s domovskou stránkou a routou /api/health. Jeho start skript nejdřív builduje a pak servíruje:

package.json
{  "scripts": {    "dev": "next dev",    "build": "next build",    "start": "next build && next start -H 0.0.0.0 -p $SERVER_PORT"  }}

Build při startu znamená, že každý restart web znovu sestaví. To je pomalejší než servírovat commitnutý build, ale server tak vždy běží přesně na commitu, který si stáhl, a v Gitu není složka .next, která by zastarala. Cenou je paměť: next build je to nejnáročnější, co malý web v Next.js za celý den dělá. Pokud konzole ukazuje, že build na nejmenším plánu padá, je to limit paměti, ne chyba - na limitu se kontejner zastaví a čistě znovu spustí, místo aby swapoval. Sleduj graf paměti během buildu a pokud se dotkne čáry, přejdi na větší plán. Nasazení Next.js na Node serveru jde dál do standalone výstupu a cache buildu.

FastAPI

app.py vytvoří aplikaci a uvicorn spouští sám, místo aby spoléhal na příkazový řádek:

app.py
if __name__ == "__main__":    port = int(os.environ.get("SERVER_PORT", os.environ.get("PORT", "8000")))    uvicorn.run(app, host="0.0.0.0", port=port)

Důvod, proč adresa a port zůstávají v kódu: Python server spouští soubor a soubor, který si spouští vlastní server, nejde nastartovat na špatné adrese zapomenutým přepínačem. requirements.txt připíná fastapi, uvicorn a python-dotenv na přesné verze a instaluje se před každým startem. Interaktivní dokumentace je na /docs od prvního spuštění. Průvodce nasazením FastAPI a Flasku pokrývá workery a produkční nastavení.

Discord bot

Bot v discord.js s jedním globálním slash příkazem, /ping. Čte DISCORD_TOKEN a když chybí, skončí srozumitelnou zprávou, místo aby selhal někde uvnitř knihovny. Bot nepotřebuje žádný příchozí port, ale pokud ho server má, starter na něm odpovídá malou JSON health kontrolou, takže uptime monitor má na co se ptát. Od Discordu žádá jen intent Guilds; čtení obsahu zpráv vyžaduje privilegovaný intent zapnutý ve Discord developer portálu a přidaný v kódu. Zbytek pokrývá článek hostování Discord bota 24/7.

Telegram bot

Echo bot v python-telegram-bot, který odpovídá na /start a opakuje jakýkoli text zpátky. Používá long polling: bot se Telegramu ptá na nové zprávy, takže k němu nemusí nic zvenku dorazit a nepotřebuje port ani doménu. To je nejjednodušší nastavení a správná výchozí volba; webhooky se vyplatí až při velkém objemu a přinášejí vlastní způsoby selhání, popsané v řešení potíží s webhooky Telegramu.

Statický web

index.html, 404.html a stylesheet v kořeni, pro webhostingový server. Není tu start skript ani port, na který by se bindovalo: vlastní webový server serveru servíruje soubory tak, jak jsou. Cokoli v kořeni webu si může návštěvník stáhnout, takže tenhle starter nemá žádné tajné údaje. Pokud později přejdeš na bundler, buď commitni sestavený výstup, nebo nasměruj Where to put the code na složku, která ho obsahuje.

Úpravy, které nerozbijí deploy#

Startery jsou určené k úpravám. Některé změny jsou bezpečné kdykoli, některé chtějí opatrnost.

Bezpečné měnit volně: routy, stránky, handlery, název aplikace, styly, přidávání souborů a složek, přidávání závislostí. Balíček přidáš pomocí npm install <name> nebo řádkem v requirements.txt, commitneš aktualizovaný lock soubor nebo requirements a pushneš. Server nainstaluje, co je uvedeno, při dalším startu. Commituj package-lock.json; díky němu instalace na serveru odpovídá té na tvém počítači. Rozdíl mezi oběma instalačními příkazy je v článku npm ci vs npm install.

Měnit opatrně: volání listen, skript start a název vstupního souboru. To jsou ta čtyři pravidla a právě tam refaktoring potichu rozbije funkční server. Přesunout server do src/index.js je v pořádku, pokud start jde s ním. Přejmenování app.py na main.py znamená změnit i soubor uvedený na kartě Startup. Zabalení aplikace do frameworku, který poslouchá na vlastním výchozím portu - mnohé to dělají, často 3000, 5000 nebo 8000 - znamená předat mu port serveru výslovně.

Nikdy necommitovat: .env, tokeny, hesla k databázím, soukromé klíče. Zkopíruj .env.example jako .env na server přes správce souborů nebo SFTP a skutečné hodnoty vyplň tam:

.env
APP_NAME=my-apiDISCORD_TOKEN=paste-the-real-token-hereDATABASE_URL=postgres://user:password@host:port/dbname

Restart nebo push deploy resetuje soubory, které pocházejí z repozitáře, a ignorovaný .env nechá na pokoji. Přeinstalace je něco jiného: první deploy nebo změna verze runtime nahradí všechno v adresáři. Nahraj .env po prvním deployi a uchovej jeho kopii někde v bezpečí - je to jediný soubor, který čerstvý deploy nedokáže znovu vytvořit.

Přidání databáze. Plány pro aplikace obsahují sloty pro databáze, které se vytvářejí v panelu s vygenerovaným hostem, uživatelem a heslem. Connection string patří do .env, ne do kódu. Pokud chceš aplikaci, databázi a cache koupit společně, balíček z karty Bundles v obchodě panelu to vyřídí jednou objednávkou se slevou.

Před každým pushem, který se týká startu, portu nebo runtime, se podívej na kartu Pre-flight check na kartě GitHub. Čte repozitář na GitHubu - jeden výpis stromu a pár malých souborů, nikdy klon - a vypíše, co se rozbije, od nejhoršího, s opravou k vložení: chybějící start skript, aplikace navázaná na localhost nebo na špatný port, chybějící build, nesoulad verze runtime, commitnutý .env (hlásí se jménem, nikdy se neotevírá). Starter ji projde hned při prvním commitu; karta ti říká, že jsi to od té doby nerozbil.

Deploy při každém pushi#

Karta GitHub má dva přepínače a ty spolu rozhodují, kdy nový kód půjde naostro.

  • Pull the latest commit every time the server starts. Restart stáhne větev a spustí nový kód. Při pushi se nestane nic; kdy restartovat, rozhoduješ ty.
  • Restart the server when someone pushes to this branch. Běžící server se do pár vteřin po pushi restartuje a vrátí se na novém commitu. Zastavený server se spustí, takže push jde naostro tak či tak.

Pro hobby bota nebo osobní API je push-to-deploy správná výchozí volba: commit, push a sleduj konzoli. Pro cokoli, na čem lidé závisí, nasazuj z větve, do které pushuješ záměrně. Nech main jako místo, kam dopadá práce, a produkční větev serveru nastav na něco jako production nebo release a mergeuj do ní, když to myslíš vážně. Každý deploy se zaznamenává, jeden záznam na deploy, takže „co teď běží“ má odpověď.

Dvě věci, které je dobré vědět, než se na to spolehneš. Za prvé, složka uvedená v Where to put the code se při každém startu vrací do stavu repozitáře: oprava, kterou jsi udělal živě ve správci souborů v souboru, který je v Gitu, se při dalším deployi zruší, a přeinstalace složku zcela vyčistí. Opravu udělej v Gitu a uploady a data drž mimo složku s deployem - v databázi nebo objektovém úložišti. Za druhé, restart je restart. Web v Next.js se znovu sestaví, bot se znovu připojí a rozpracované požadavky se zahodí. Deploy bez výpadku na malém serveru a graceful shutdown jsou další krok, jakmile na tom začne záležet.

Deploy token, kterým panel stahuje tvůj kód, se vystavuje znovu při každém startu serveru. Na serveru není žádný dlouhodobý klíč k GitHubu, který by mohl uniknout.

Když první start přesto selže#

Starter odstraní většinu selhání prvního deploye, ne všechna. Tohle jsou ta, která zbývají.

  • Stránka se nenačte, ale konzole vypadá v pořádku. Pravděpodobně míříš na špatný port, nebo něco, co jsi přidal, poslouchá na vlastním portu. Najdi v konzoli číslo portu v řádku „listening“ a porovnej ho s portem na stránce serveru.
  • `DISCORD_TOKEN is not set` nebo `TELEGRAM_BOT_TOKEN is not set`. Bot startery se bez tokenu záměrně zastaví. Nahraj .env s proměnnou a restartuj.
  • Bot se přihlásí, ale nic neodpovídá. U Discordu musí být bot pozvaný na server s oprávněním applications.commands, než se objeví slash příkazy. U Telegramu zkontroluj, že žádná jiná kopie bota - třeba na tvém notebooku - nepolluje se stejným tokenem; dva pollery se perou o stejné updaty.
  • Instalace selže s chybou verze. Runtime version vybraná na kartě je starší, než kód potřebuje. Její změna server přestaví na novém image, což nahradí soubory v jeho adresáři repozitářem; databáze a zálohy zůstanou nedotčené.
  • Build Next.js se uprostřed zabije. Limit paměti. Zkontroluj graf paměti během buildu; řešením je větší plán nebo lehčí build, ne opakování.
  • Server pořád padá. Smyčka pádů se zaznamená: hlídač počítá pády, které jsi nevyvolal, a tři za hodinu vloží varování na stránku serveru a otevřou ticket. Čti první chybu v konzoli, ne poslední.
  • Repozitář není v seznamu. GitHub App vidí jen repozitáře, které jsi s ní sdílel. Přidej nový repozitář v Manage repository access.

Žádná šablona pro tvůj stack#

Servery s Bunem, Denem, Go, Javou, Rustem, .NET a Laravelem zatím starter nemají, ale všechny začínají zástupnou stránkou a stejná čtyři pravidla zajistí, že prázdný repozitář se nasadí na první pokus.

U Go server při každém startu spustí go build a neúspěšný build start zastaví, místo aby spustil starý kód. Minimální main.go:

main.go
package mainimport (    "fmt"    "net/http"    "os")func main() {    port := os.Getenv("SERVER_PORT")    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {        fmt.Fprintln(w, "hello")    })    http.ListenAndServe("0.0.0.0:"+port, nil)}

Commitni ho spolu s go.mod a pre-flight kontrola porovná jeho verzi Go s tou na serveru. Delší verzi najdeš v článku nasazení webové služby v Go.

U Bunu se skript start v package.json spustí po bun install. U Dena se úloha start v deno.json spustí příkazem deno task start - a pozor, Deno.serve má výchozí port 8000, takže mu předej port serveru. Bun nebo Deno na malém serveru obě porovnává. U Javy funguje jakýkoli spustitelný jar: Spring Boot, Quarkus, Micronaut nebo Ktor na Javě 17, 21 nebo 25, s portem nastaveným ze SERVER_PORT.

FAQ#

Musím držet svůj repozitář synchronizovaný se šablonou?

Ne. Repozitář vytvořený ze šablony na GitHubu na ni nemá žádnou vazbu ani společnou historii. Aktualizace šablony se k tobě nedostanou a tvé commity se nedostanou k nikomu jinému. Pokud novější verze starteru opraví něco, na čem ti záleží, zkopíruj změnu ručně jako jakýkoli jiný kód.

Může být můj repozitář soukromý?

Ano. Na stránce vytváření na GitHubu zvol soukromý. Panel nasazuje přes GitHub App s krátkodobými tokeny, takže soukromé repozitáře se nasazují stejně jako veřejné. Pokud později zapneš pull request s AI kontextem, veřejný repozitář dostane jen obecná pravidla a žádné podrobnosti o tvém serveru.

Smaže nasazení šablony to, co už na serveru je?

Ano, deploy server přeinstaluje z repozitáře: soubory v jeho adresáři se nahradí a vše necommitnuté se ztratí. Databáze a zálohy zůstanou nedotčené. Na zbrusu novém serveru nemáš co ztratit; na serveru, na kterém už pracuješ, nejdřív udělej zálohu.

Proč můj server s Node.js nezobrazuje zástupnou stránku?

Zástupná stránka se zapisuje u každé runtime řady kromě Node.js. Nový server s Node.js startuje prázdný, takže před prvním startem nasaď repozitář - starter nebo vlastní.

Mohu použít starter na jiném hostingu?

Ano. Nic v nich není vázané na konkrétní panel, jen čtou nejdřív SERVER_PORT, a pak se vrací k PORT a lokálnímu výchozímu portu. To pokrývá většinu platforem, které nastavují proměnnou s portem, i tvůj vlastní počítač.

Jak dlouho trvá, než push půjde naostro?

Při zapnutém push deployi se běžící server restartuje do pár vteřin po pushi. Celková doba závisí na aplikaci: Express API je zpět téměř hned, zatímco web v Next.js se při startu znovu builduje a trvá tak dlouho, jak dlouho next build na daném plánu běží.

Pomohlo vám to?