Wdrażanie Astro 5 na Dokploy
Jakub Nalewajk · 10 marca 2026
Na tej stronie
- 01 Dlaczego self-hosting?
- 02 Wymagania
- 03 Krok 1: Konfiguracja Astro dla Node.js
- 04 Krok 2: Napisz Dockerfile
- 05 Krok 3: Konfiguracja Dokploy
- 06 Zmienne środowiskowe
- 07 Konfiguracja domeny
- 08 Krok 4: Konfiguracja DNS
- 09 Krok 5: Konfiguracja Traefik
- 10 Krok 6: Zmienne środowiskowe build-time vs runtime
- 11 Krok 7: Wdrożenie
- 12 Krok 8: Auto-Deploy
- 13 Problem z SMTP
- 14 Efekt końcowy
Większość poradników o Astro mówi ci, żebyś wdrożył na Vercel i tyle. A co jeśli chcesz mieć kontrolę nad swoją infrastrukturą, nie być przywiązanym do jednego dostawcy i móc uruchamiać wiele aplikacji na jednym VPS? Dlatego przeniosłem swoje portfolio z Vercel na self-hosted setup z Dokploy.
W tym poradniku przeprowadzę cię przez proces wdrażania strony Astro 5 z SSR na twoim VPS za pomocą Dokploy, Traefik jako reverse proxy i Dockera.
Dlaczego self-hosting?
Vercel działa, ale self-hosting daje ci:
- Kontrolę nad kosztami - jeden VPS może obsługiwać wiele aplikacji zamiast płacenia za każdy projekt
- Pełną kontrolę nad infrastrukturą - żadnych niespodzianek, limitów ani vendor lock-in
- Szansę na naukę - zrozumienie Dockera, reverse proxy i sieci
- Prywatność - twoje dane zostają na twoim serwerze
Uruchamiam swoje portfolio, dwie aplikacje Next.js i serwer bazy danych na jednym VPS za €7/miesiąc.
Wymagania
Zanim zaczniemy, będziesz potrzebował:
- VPS z Ubuntu 22+ (ja używam Hetzner, ale każdy dostawca działa)
- Nazwę domeny z dostępem do DNS (ja używam Cloudflare)
- Dokploy zainstalowane na VPS
- Projekt Astro 5 z adapterem Node.js
Krok 1: Konfiguracja Astro dla Node.js
Astro potrzebuje adaptera @astrojs/node, żeby działać jako samodzielny serwer zamiast generować statyczne pliki dla CDN.
npm install @astrojs/node
Zaktualizuj swój astro.config.mjs:
import node from '@astrojs/node'
export default defineConfig({
adapter: node({
mode: 'standalone',
}),
// ... reszta konfiguracji
})
Tryb standalone tworzy samodzielny serwer, który możesz uruchomić za pomocą node ./dist/server/entry.mjs.
Krok 2: Napisz Dockerfile
To jest miejsce, gdzie większość ludzi się zatrzymuje. Oto wieloetapowy Dockerfile, który utrzymuje obraz mały:
FROM node:22-alpine AS base
WORKDIR /app
FROM base AS deps
COPY package.json package-lock.json ./
RUN npm ci
FROM base AS build
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runtime
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY package.json .
ENV HOST=0.0.0.0
ENV PORT=3000
EXPOSE 3000
CMD ["node", "./dist/server/entry.mjs"]
Kluczowe decyzje:
- Wieloetapowy build - etap
depscachujenode_modules, etapbuildkompiluje, a etapruntimezawiera tylko to, co potrzebne do uruchomienia HOST=0.0.0.0- bez tego serwer nasłuchuje tylko na localhost wewnątrz kontenera i Traefik nie może do niego dotrzećPORT=3000- dopasuj to do konfiguracji domeny w Dokploy
Nie zapomnij o .dockerignore:
node_modules
dist
.git
.env
Krok 3: Konfiguracja Dokploy
Jeśli nie masz jeszcze zainstalowanego Dokploy:
curl -sSL https://dokploy.com/install.sh | sh
Po uruchomieniu Dokploy stwórz aplikację:
- Przejdź do Projects → Create Project
- Dodaj Application → GitHub jako dostawcę
- Połącz swoje repozytorium i wybierz branch
- Ustaw typ buildu na Dockerfile
Zmienne środowiskowe
W Environment Settings Dokploy dodaj swoje zmienne:
PUBLIC_RECAPTCHA_KEY=twój_klucz
RECAPTCHA_KEY=twój_sekretny_klucz
RESEND_API_KEY=re_xxxxx
Są one wstrzykiwane w runtime przez Dockera, więc nie potrzebujesz ich w Dockerfile.
Konfiguracja domeny
W sekcji Domains:
- Dodaj swoją domenę (np.
jnalewajk.me) - Ustaw port na
3000(zgodny zENV PORTw Dockerfile) - Wybierz HTTPS z Let’s Encrypt
- Kliknij Generate, żeby utworzyć konfigurację Traefik
Krok 4: Konfiguracja DNS
W swoim dostawcy DNS (ja używam Cloudflare) skieruj domenę na VPS:
| Typ | Nazwa | Zawartość | Proxy |
|---|---|---|---|
| A | @ | twoje.ip.vps | DNS only |
| CNAME | www | twojadomena.com | DNS only |
Ważne: Użyj DNS only (szara chmurka w Cloudflare), nie Proxied. Traefik obsługuje SSL przez Let’s Encrypt, a proxy Cloudflare powodowałoby konflikty certyfikatów.
Krok 5: Konfiguracja Traefik
Dokploy automatycznie generuje konfigurację Traefik dla twojej aplikacji. Prawdopodobnie będziesz chciał ją dostosować dla kompresji i przekierowań www. Oto jak wygląda moja konfiguracja:
http:
routers:
app-router:
rule: Host(`jnalewajk.me`)
service: app-service
middlewares:
- redirect-to-https
entryPoints:
- web
app-router-secure:
rule: Host(`jnalewajk.me`)
service: app-service
middlewares:
- compress
entryPoints:
- websecure
tls:
certResolver: letsencrypt
www-router:
rule: Host(`www.jnalewajk.me`)
service: app-service
middlewares:
- www-to-non-www
entryPoints:
- websecure
tls:
certResolver: letsencrypt
middlewares:
compress:
compress: {}
www-to-non-www:
redirectRegex:
regex: "^https?://www\\.jnalewajk\\.me/(.*)"
replacement: 'https://jnalewajk.me/${1}'
permanent: true
services:
app-service:
loadBalancer:
servers:
- url: http://twój-kontener:3000
passHostHeader: true
Middleware compress włącza kompresję gzip/Brotli, a www-to-non-www obsługuje przekierowania 301 z www na nagą domenę.
Krok 6: Zmienne środowiskowe build-time vs runtime
To częsty problem z Astro i Dockerem. Są dwa typy zmiennych:
Build-time (potrzebne podczas npm run build):
- Zmienne
PUBLIC_*, które są wstawiane do JavaScript po stronie klienta - Muszą być przekazane jako
ARGw Dockerfile
FROM base AS build
ARG PUBLIC_RECAPTCHA_KEY
ENV PUBLIC_RECAPTCHA_KEY=$PUBLIC_RECAPTCHA_KEY
RUN npm run build
W Dokploy ustaw je w sekcji Build Arguments, nie Environment Variables.
Runtime (potrzebne gdy serwer działa):
- Sekrety po stronie serwera jak klucze API
- Idą do sekcji Environment Variables Dokploy i są wstrzykiwane do kontenera w runtime
Krok 7: Wdrożenie
Kliknij Deploy w Dokploy. Wykona:
- Klonowanie repozytorium
- Budowanie obrazu Docker za pomocą Dockerfile
- Uruchomienie kontenera
- Traefik automatycznie kieruje ruch i provisionuje SSL
Sprawdź logi budowania pod kątem błędów. Częste problemy:
- Build nie działa - brakujące build args dla zmiennych
PUBLIC_* - Kontener startuje, ale 502 - zły port lub
HOSTnie ustawiony na0.0.0.0 - SSL nie działa - DNS jeszcze się nie propagował lub używasz trybu proxy Cloudflare
Krok 8: Auto-Deploy
W Dokploy włącz auto-deploy z repozytorium GitHub:
- Przejdź do ustawień aplikacji
- Włącz Auto Deploy na push do twojego brancha
- Dokploy automatycznie przebuduje i wdroży przy każdym pushu
Problem z SMTP
Jeśli twoja aplikacja wysyła emaile (jak formularz kontaktowy), pamiętaj, że wielu dostawców VPS blokuje wychodzące porty SMTP (25, 465, 587). Odkryłem to, gdy moja konfiguracja Nodemailer zawieszała się w nieskończoność.
Rozwiązanie: użyj serwisu emailowego opartego na API jak Resend zamiast SMTP. Używa HTTPS (port 443), który nigdy nie jest blokowany.
import { Resend } from 'resend'
const resend = new Resend(process.env.RESEND_API_KEY)
await resend.emails.send({
from: 'noreply@twojadomena.com',
to: 'ty@gmail.com',
subject: 'Formularz kontaktowy',
html: renderedHtml,
})
Efekt końcowy
Moje portfolio działa na VPS Hetzner obok dwóch innych aplikacji z automatycznym SSL przez Let’s Encrypt, kompresją gzip przez Traefik i auto-deploy z GitHub. Wszystko za €7/miesiąc.
Konfiguracja zajęła mi około godziny i od tamtej pory nie musiałem przy tym nic ruszać. Jeśli znasz podstawy Dockera, nie ma powodu, żeby zostawać na darmowym planie Vercel z jego ograniczeniami.
Kod źródłowy mojego portfolio jest na GitHubie, jeśli chcesz zobaczyć Dockerfile i konfigurację.
Jeśli budujesz wielojęzyczną stronę w Astro, napisałem też kompletny poradnik o dodawaniu i18n do Astro 5 bez bibliotek. A jeśli zastanawiasz się nad kosztami prowadzenia takiej strony, sprawdź ile kosztuje strona internetowa w 2026.