This commit is contained in:
Felix Klement committed 2026-10-04 19:49:09 +02:00
1 parent 8385db6ebf
commit 5af2d78328
4 files changed
+106

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
.git
.gitignore
.DS_Store
**/.DS_Store
node_modules
dist
.astro
product_repo
.ds-sync
ds-bundle
.design-sync/.cache
.design-sync/learnings
.design-sync/node_modules
docs
Dockerfile
.dockerignore
*.log
.env
.env.*
+19
View File
@@ -0,0 +1,19 @@
# syntax=docker/dockerfile:1
# Build the static site.
FROM node:22-bookworm-slim AS build
WORKDIR /app
ENV ASTRO_TELEMETRY_DISABLED=1 \
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
COPY package.json package-lock.json ./
RUN npm ci --no-audit --no-fund
COPY . .
RUN npm run build
# Serve dist/ with nginx.
FROM nginx:1.27-alpine AS runtime
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget -qO- http://127.0.0.1/healthz || exit 1
+15
View File
@@ -13,6 +13,21 @@ npm run preview # serve dist/
npm run check # Astro + TypeScript check npm run check # Astro + TypeScript check
``` ```
## Docker / Dokploy
The `Dockerfile` builds the site with Node and serves `dist/` from nginx on port 80
(config in `docker/nginx.conf`: clean URLs without trailing slash, 404 page, gzip, long caching for
`/_astro/`, health check at `/healthz`).
```sh
docker build -t ciphercell .
docker run --rm -p 8080:80 ciphercell # http://localhost:8080
```
In Dokploy: create an Application from this repository, set Build Type to **Dockerfile**
(path `Dockerfile`), and under Domains add the domain with container port **80** and HTTPS on.
TLS is handled by Dokploy's Traefik.
## Where things live ## Where things live
| Path | Purpose | | Path | Purpose |
+53
View File
@@ -0,0 +1,53 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# TLS terminates at Dokploy's Traefik; keep redirects relative so they stay on https.
absolute_redirect off;
server_tokens off;
gzip on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml application/xml application/javascript application/json image/svg+xml;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
location = /healthz {
access_log off;
default_type text/plain;
return 200 "ok\n";
}
# trailingSlash: 'never' — /team is served from /team/index.html; /team/ redirects to /team.
location ~ ^(.+)/$ {
return 301 $1$is_args$args;
}
location / {
try_files $uri $uri.html $uri/index.html =404;
}
# Astro's hashed build assets never change.
location ^~ /_astro/ {
add_header Cache-Control "public, max-age=31536000, immutable" always;
add_header X-Content-Type-Options "nosniff" always;
try_files $uri =404;
}
location ~* \.(?:woff2|mp4|webm|avif|webp|jpg|jpeg|png|svg)$ {
add_header Cache-Control "public, max-age=2592000" always;
add_header X-Content-Type-Options "nosniff" always;
try_files $uri =404;
}
error_page 404 /404.html;
location = /404.html {
internal;
}
}