chore: add Docker deployment behind Caddy

Build the static Next.js export in a reproducible container and expose it
through the existing Caddy network and upstream service name.
This commit is contained in:
2026-09-06 15:01:56 +03:30
parent e45a2fc14a
commit 463e72a404
5 changed files with 115 additions and 0 deletions

15
.dockerignore Normal file
View File

@@ -0,0 +1,15 @@
.git
.gitignore
.next
out
node_modules
.env
.env.*
*.log
npm-debug.log*
Dockerfile*
compose*.yaml
compose*.yml

23
DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,23 @@
# Deployment
This project builds the Next.js static export in a Node container and serves the
generated files from Nginx on port 80. The container joins the existing
`caddy_proxy` Docker network under the `static-site` service name expected by
Caddy.
## Deploy or update
From the project directory on the server, run:
```sh
docker compose up --build -d
```
The external `caddy_proxy` network must already exist and Caddy must be attached
to it. No host port is published because Caddy is the public entry point and
terminates TLS for `amiirkhl.ir` and `www.amiirkhl.ir`.
If the previous `static-site` container was created from a different Compose
project directory, remove that old stack once before the first deployment to
avoid a Docker container-name conflict. Updates from this project then use only
the command above.

21
Dockerfile Normal file
View File

@@ -0,0 +1,21 @@
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine AS runtime
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/out/ /usr/share/nginx/html/
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://127.0.0.1/ || exit 1
CMD ["nginx", "-g", "daemon off;"]

15
compose.yaml Normal file
View File

@@ -0,0 +1,15 @@
services:
static-site:
image: amiirkhl-portfolio:latest
build:
context: .
dockerfile: Dockerfile
container_name: static-site
restart: unless-stopped
networks:
- caddy_proxy
networks:
caddy_proxy:
external: true
name: caddy_proxy

41
nginx.conf Normal file
View File

@@ -0,0 +1,41 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
charset utf-8;
server_tokens off;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types
application/javascript
application/json
application/xml
image/svg+xml
text/css
text/plain;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location ^~ /_next/static/ {
try_files $uri =404;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
access_log off;
}
location / {
try_files $uri $uri.html $uri/ =404;
}
error_page 404 /404.html;
location = /404.html {
internal;
}
}