feat: add Docker support with Dockerfile and docker-compose configuration

This commit is contained in:
eafonyang
2026-06-25 16:14:04 +08:00
parent 6073f4d598
commit 2d4e98d53b
10 changed files with 262 additions and 1 deletions
+21 -1
View File
@@ -1,13 +1,33 @@
.git
.github
.next
.next-dev
.next/cache
node_modules
npm-debug.log*
.env
.env.*
deploy-packages
output
data
media
files
videos
public
docs
*.md
*.dump
*.tgz
*.tar.gz
cloudflare/.wrangler
cloudflare
.wrangler
.claude
.playwright-cli
.tmp
.turbo
tsconfig.tsbuildinfo
tmp-*
**/.DS_Store
**/._*
__MACOSX
src/seed/raw
+5
View File
@@ -25,6 +25,11 @@ videos
deploy-packages
output
# nginx TLS material (upload fullchain.pem + privkey.pem on the server)
nginx/certs/*.pem
nginx/certs/*.key
data/
# misc
.DS_Store
._*
+51
View File
@@ -0,0 +1,51 @@
# syntax=docker/dockerfile:1
FROM uhub.service.ucloud.cn/mysql-images/node:22-bookworm-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
npm config set registry https://registry.npmmirror.com \
&& npm ci
FROM uhub.service.ucloud.cn/mysql-images/node:22-bookworm-slim AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ARG NEXT_PUBLIC_SITE_URL
ARG PAYLOAD_SECRET
ARG DATABASE_URI
ENV NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL
ENV PAYLOAD_SECRET=$PAYLOAD_SECRET
ENV DATABASE_URI=$DATABASE_URI
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
FROM uhub.service.ucloud.cn/mysql-images/node:22-bookworm-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 --gid nodejs nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
RUN mkdir -p media files videos \
&& chown -R nextjs:nodejs media files videos
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]
+69
View File
@@ -0,0 +1,69 @@
services:
app:
build:
context: .
dockerfile: Dockerfile
# Enable BuildKit layer/cache mounts: DOCKER_BUILDKIT=1 docker compose build app
args:
NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL}
PAYLOAD_SECRET: ${PAYLOAD_SECRET}
DATABASE_URI: ${DATABASE_URI}
container_name: eversolo-web
restart: unless-stopped
env_file: .env
expose:
- "3000"
volumes:
- ./data/media:/app/media
- ./data/files:/app/files
- ./data/videos:/app/videos
networks:
- web
nginx:
image: uhub.service.ucloud.cn/mysql-images/nginx:latest
container_name: eversolo-nginx
restart: unless-stopped
depends_on:
- app
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./nginx/certs:/etc/nginx/certs:ro
- ./data/media:/srv/uploads/media:ro
- ./data/files:/srv/uploads/files:ro
- ./data/videos:/srv/uploads/videos:ro
networks:
- web
bootstrap:
image: uhub.service.ucloud.cn/mysql-images/node:22-bookworm-slim
working_dir: /app
env_file: .env
volumes:
- .:/app
- bootstrap_node_modules:/app/node_modules
- ./data/media:/app/media
- ./data/files:/app/files
- ./data/videos:/app/videos
command: >
bash -lc "
npm ci --include=dev &&
npm run payload:migrate &&
npm run payload:migrate:status &&
npm run seed:import -- --live &&
npx tsx ./src/scripts/create-admin.ts
"
profiles: [bootstrap]
networks:
- web
networks:
web:
driver: bridge
volumes:
bootstrap_node_modules:
+1
View File
@@ -7,6 +7,7 @@ const PUBLIC_PAGE_CACHE_CONTROL = 'public, max-age=0, s-maxage=300, stale-while-
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
reactStrictMode: true,
allowedDevOrigins: ['127.0.0.1', '192.168.1.252'],
distDir: process.env.NEXT_DIST_DIR || '.next',
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -0,0 +1 @@
+84
View File
@@ -0,0 +1,84 @@
upstream eversolo_app {
server app:3000;
keepalive 32;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name www.luxsin.net luxsin.net;
location / {
return 301 https://www.luxsin.net$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name www.luxsin.net;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options SAMEORIGIN always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
# Payload uploads served directly from the persistent data volume (see docker-compose nginx mounts).
location /media/ {
alias /srv/uploads/media/;
access_log off;
expires 30d;
add_header Cache-Control "public, max-age=2592000, immutable";
}
location /files/ {
alias /srv/uploads/files/;
access_log off;
expires 7d;
add_header Cache-Control "public, max-age=604800";
}
location /videos/ {
alias /srv/uploads/videos/;
access_log off;
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}
location / {
proxy_pass http://eversolo_app;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name luxsin.net;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
return 301 https://www.luxsin.net$request_uri;
}
+28
View File
@@ -0,0 +1,28 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
client_max_body_size 100m;
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
include /etc/nginx/conf.d/*.conf;
}