Add Docker deploy for Caddy production at cyd.smallzhiyuns.com.

Standalone Next image, local firmware sync volume, and docs for the existing host-network Caddy reverse proxy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-19 20:41:08 +08:00
parent e2fa28e501
commit 2020f586d9
10 changed files with 102 additions and 11 deletions

14
.dockerignore Normal file
View File

@@ -0,0 +1,14 @@
node_modules
.next
.git
.gitignore
*.md
.env*
!.env.example
scripts/_ssh*
scripts/*.py
.cursor
npm-debug.log*
Dockerfile*
docker-compose*.yml
.dockerignore

4
.gitignore vendored
View File

@@ -37,7 +37,9 @@ yarn-error.log*
!.env.example
# mirrored firmwares (run npm run sync:firmware for public deploy)
/firmware/
# Keep empty dir in git via .gitkeep when needed for Docker COPY
/firmware/**
!/firmware/.gitkeep
# vercel
.vercel

36
Dockerfile Normal file
View File

@@ -0,0 +1,36 @@
# CYD Flasher — production image (Next.js standalone)
FROM node:20-bookworm-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
FROM node:20-bookworm-slim AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN mkdir -p public
ENV NEXT_TELEMETRY_DISABLED=1
ARG NEXT_PUBLIC_SITE_URL=https://cyd.smallzhiyuns.com
ENV NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL
RUN npm run build
FROM node:20-bookworm-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
ENV NEXT_PUBLIC_SITE_URL=https://cyd.smallzhiyuns.com
ENV CYD_FIRMWARE_ROOT=/app/firmware
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 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
COPY --chown=nextjs:nodejs firmware ./firmware
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]

View File

@@ -73,19 +73,26 @@ Create `meta.json` beside the `.bin` files:
Without `meta.json`, the catalog still works from `VERSION.txt`.
## Public deploy
## Public deploy (Docker + Caddy)
Web Serial requires **HTTPS** (or localhost).
Production: **https://cyd.smallzhiyuns.com**
Server layout: `/home/dsx2016/docker/cydweb` + Caddy reverse proxy `127.0.0.1:3020`.
```powershell
npm run sync:firmware
# On server:
cd /home/dsx2016/docker/cydweb
docker compose up -d --build
# Reload Caddy after Caddyfile changes:
cd /home/dsx2016/docker/caddy && docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile
```
```env
NEXT_PUBLIC_SITE_URL=https://your-domain.example
NEXT_PUBLIC_SITE_URL=https://cyd.smallzhiyuns.com
CYD_FIRMWARE_ROOT=/app/firmware
```
Then `npm run build && npm start` (or any Next.js host). `firmware/` mirror is gitignored.
Web Serial requires **HTTPS** (or localhost).
## Scripts

18
docker-compose.yml Normal file
View File

@@ -0,0 +1,18 @@
services:
cydweb:
build:
context: .
args:
NEXT_PUBLIC_SITE_URL: https://cyd.smallzhiyuns.com
image: cydweb:latest
container_name: cydweb
restart: unless-stopped
ports:
- "127.0.0.1:3020:3000"
environment:
- NODE_ENV=production
- NEXT_PUBLIC_SITE_URL=https://cyd.smallzhiyuns.com
- CYD_FIRMWARE_ROOT=/app/firmware
volumes:
# Live-update firmwares without rebuild (host path populated by sync)
- ./firmware:/app/firmware:ro

0
firmware/.gitkeep Normal file
View File

View File

@@ -3,6 +3,8 @@ import createNextIntlPlugin from "next-intl/plugin";
const withNextIntl = createNextIntlPlugin("./i18n/request.ts");
const nextConfig: NextConfig = {};
const nextConfig: NextConfig = {
output: "standalone",
};
export default withNextIntl(nextConfig);

20
package-lock.json generated
View File

@@ -1,17 +1,18 @@
{
"name": "cydweb",
"version": "0.1.0",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "cydweb",
"version": "0.1.0",
"version": "1.0.0",
"dependencies": {
"@radix-ui/react-radio-group": "^1.5.1",
"@radix-ui/react-select": "^2.4.1",
"@radix-ui/react-separator": "^1.2.0",
"@radix-ui/react-slot": "^1.5.0",
"@swc/helpers": "0.5.23",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^1.59.0",
@@ -2341,9 +2342,9 @@
"license": "Apache-2.0"
},
"node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
"integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
"version": "0.5.23",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz",
"integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.8.0"
@@ -6352,6 +6353,15 @@
}
}
},
"node_modules/next/node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
"integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.8.0"
}
},
"node_modules/next/node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",

View File

@@ -15,6 +15,7 @@
"@radix-ui/react-select": "^2.4.1",
"@radix-ui/react-separator": "^1.2.0",
"@radix-ui/react-slot": "^1.5.0",
"@swc/helpers": "0.5.23",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^1.59.0",

1
public/.gitkeep Normal file
View File

@@ -0,0 +1 @@