Despliegue
En esta página
Una compilación de sitelo son archivos estáticos y ya: sitelo build escribe HTML, CSS y JS en dist/. Sirve cualquier hosting estático — las configuraciones de abajo solo asumen npm run build → dist/.
Las URLs limpias son directorios con index.html (/about/index.html → /about), así que las URLs bonitas funcionan de entrada, sin reglas de redirección. El 404.html se emite automáticamente: es la convención que entienden Netlify, Cloudflare Pages y GitHub Pages.
Hay versiones listas para copiar de todo esto en el ejemplo básico (examples/basic en el repositorio).
Hosting estático
Estos servicios compilan el sitio y sirven dist/ desde su propia CDN.
Netlify · Vercel · Cloudflare · AWS Amplify · AWS S3 + CloudFront · Azure Static Web Apps · Firebase Hosting · GitHub Pages · GitLab Pages · Render · DigitalOcean App Platform
Netlify
[build]
command = "npm run build"
publish = "dist"Vercel
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": null,
"buildCommand": "npm run build",
"outputDirectory": "dist",
"installCommand": "npm install"
}Cloudflare
Cloudflare recomienda ahora Workers en lugar de Pages para proyectos nuevos. Con esta configuración, npx wrangler deploy compila el sitio y sube dist/, y si conectas el repositorio en el panel de Cloudflare se ejecuta el mismo comando en cada push. html_handling: "drop-trailing-slash" sirve /about sin redirección, y las URL desconocidas reciben 404.html.
// Cloudflare Workers
{
"name": "my-site",
"compatibility_date": "2026-10-01",
"build": {
"command": "npm run build"
},
"assets": {
"directory": "./dist",
"not_found_handling": "404-page",
"html_handling": "drop-trailing-slash"
}
}¿Sigues en Pages? Pon npm run build como comando de compilación y dist como directorio de salida, o sube una compilación local con npx wrangler pages deploy dist.
AWS Amplify
# Alojamiento en AWS Amplify
version: 1
frontend:
phases:
preBuild:
commands:
- npm install
build:
commands:
- npm run build
artifacts:
baseDirectory: dist
files:
- '**/*'
cache:
paths:
- node_modules/**/*AWS S3 + CloudFront
Mantén el bucket privado y pon CloudFront delante con origin access control. CloudFront solo asigna / a index.html, así que asocia esta función a las solicitudes de visor de la distribución para servir las URL limpias de sitelo.
function handler(event) {
var request = event.request
var uri = request.uri
if (uri.endsWith('/')) {
request.uri += 'index.html'
} else if (uri.slice(uri.lastIndexOf('/') + 1).indexOf('.') === -1) {
request.uri += '/index.html'
}
return request
}Un bucket privado responde con 403 cuando falta un archivo, así que añade respuestas de error personalizadas para 403 y 404 que devuelvan /404.html con estado 404. Después sube cada compilación y vacía la caché:
npm run build
aws s3 sync dist/ s3://my-bucket --delete
aws cloudfront create-invalidation --distribution-id MY_DISTRIBUTION_ID --paths "/*"Azure Static Web Apps
Crea la Static Web App en el portal de Azure con / como ubicación de la app y dist como ubicación de salida; Azure añade al repositorio un workflow de GitHub Actions que ejecuta npm run build. Pon este archivo en public/ para que la compilación lo copie a dist/: sin él, Azure responde a las URL desconocidas con su propia página de error en lugar de 404.html.
{
"responseOverrides": {
"404": {
"rewrite": "/404.html"
}
}
}Firebase Hosting
En Firebase Hosting, elige un proyecto con firebase use --add y ejecuta firebase deploy: el hook predeploy compila primero. Las URL desconocidas reciben 404.html automáticamente, y trailingSlash: false sirve /about sin redirección.
{
"hosting": {
"public": "dist",
"predeploy": "npm run build",
"trailingSlash": false
}
}GitHub Pages
# GitHub Pages
name: Deploy
on:
push:
branches: [main]
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
- run: npm ci && npm run build
- uses: actions/upload-pages-artifact@v5
with:
path: dist
- uses: actions/deploy-pages@v5¿Despliegas bajo una subruta (user.github.io/repo)? Compila con --base /repo/.
GitLab Pages
GitLab sirve 404.html y las URL de directorio por sí solo, así que el job solo compila y publica dist/.
# GitLab Pages
deploy-pages:
image: node:24
script:
- npm ci
- npm run build
pages:
publish: dist
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCHRender
Añade el Blueprint de abajo al repositorio, o crea un sitio estático desde el panel con el mismo comando de compilación y directorio de publicación. Las URL limpias y 404.html funcionan sin reglas de redirección.
# Render
services:
- type: web
name: my-site
runtime: static
buildCommand: npm install && npm run build
staticPublishPath: ./distDigitalOcean App Platform
Pon tu repositorio en github.repo y crea la app con doctl apps create --spec .do/app.yaml, o pega la especificación en el panel. App Platform resuelve las URL de directorio y sirve 404.html por defecto.
# DigitalOcean App Platform
name: my-site
static_sites:
- name: site
github:
repo: your-name/your-site
branch: main
deploy_on_push: true
build_command: npm run build
output_dir: distHosts de contenedores
Estos servicios ejecutan un contenedor, y un solo Dockerfile sirve para todos: Node compila el sitio y Caddy sirve dist/ con URL limpias y responde a las desconocidas con 404.html. Caddy escucha en PORT cuando el servicio lo define, y en el puerto 80 si no. Añade los tres archivos a la raíz del proyecto.
Railway · Fly.io · Heroku · Google Cloud Run
FROM node:24-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM caddy:2-alpine
COPY Caddyfile /etc/caddy/Caddyfile
COPY --from=build /app/dist /app/distnode_modules
dist
.git:{$PORT:80} {
root * /app/dist
encode zstd gzip
try_files {path} {path}/index.html
file_server
handle_errors {
rewrite * /{err.status_code}.html
file_server
}
}Railway
Railway compila el Dockerfile siempre que lo encuentra, así que no hay nada que configurar. Sin el Dockerfile, añade la variable de servicio RAILPACK_SPA_OUTPUT_DIR=dist y conserva el Caddyfile: Railpack servirá dist/ a través de él en lugar de su configuración por defecto para SPA, que responde a las URL desconocidas con la página de inicio.
Fly.io
Ejecuta fly launch para crear la app y luego fly deploy.
# Fly.io
app = "my-site"
[http_service]
internal_port = 80
force_https = true
auto_stop_machines = "stop"
auto_start_machines = true
min_machines_running = 0Heroku
Heroku compila el Dockerfile a través de heroku.yml. Cambia la app al stack de contenedores una vez con heroku stack:set container y luego ejecuta git push heroku main.
# Heroku
build:
docker:
web: DockerfileGoogle Cloud Run
Ejecuta gcloud run deploy --source . desde la raíz del proyecto: Cloud Build compila el Dockerfile y Cloud Run lo sirve.
Tu propio servidor
Copia la compilación al servidor con rsync -a --delete dist/ you@server:/var/www/my-site/ y sírvela con Caddy o nginx: las URL limpias y 404.html funcionan igual que en los servicios de arriba. Caddy obtiene por sí solo un certificado HTTPS para el dominio; con nginx, añade uno con certbot.
example.com {
root * /var/www/my-site
encode zstd gzip
try_files {path} {path}/index.html
file_server
handle_errors {
rewrite * /{err.status_code}.html
file_server
}
}server {
listen 80;
server_name example.com;
root /var/www/my-site;
location / {
try_files $uri $uri/index.html =404;
}
error_page 404 /404.html;
}Antes de publicar
- Define
siteensitelo.config.jspara que se genere elsitemap.xml— consulta Configuración - Añade un
src/404.ht.jspara tener una página de «no encontrado» con tu identidad (si no, se emite una por defecto) sitelo previewsirve la compilación de producción en local para una última revisión