feat: add Docker support with Dockerfile and docker-compose configuration
This commit is contained in:
+21
-1
@@ -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
|
||||
|
||||
@@ -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
@@ -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"]
|
||||
@@ -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:
|
||||
@@ -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',
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user