diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..73c5372 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +.git +.gitignore +.next +out +node_modules + +.env +.env.* + +*.log +npm-debug.log* + +Dockerfile* +compose*.yaml +compose*.yml diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..5d4a301 --- /dev/null +++ b/DEPLOYMENT.md @@ -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. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..89e562c --- /dev/null +++ b/Dockerfile @@ -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;"] diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..c2e1de1 --- /dev/null +++ b/compose.yaml @@ -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 diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..2a3d94d --- /dev/null +++ b/nginx.conf @@ -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; + } +}