diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b78f2ef --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +node_modules +npm-debug.log +.next +out +dist +.git +.gitignore +README.md +.env +.env.local +.env.development +.env.production +Dockerfile +docker-compose.yml +.dockerignore \ No newline at end of file diff --git a/DOCKER-README.md b/DOCKER-README.md new file mode 100644 index 0000000..0f65675 --- /dev/null +++ b/DOCKER-README.md @@ -0,0 +1,221 @@ +# 🐳 OpenClaw101 容器化部署指南 + +## 🚀 快速部署 + +使用 `build-docker-run.sh` 脚本可以一键构建和运行 OpenClaw101 容器: + +```bash +# 1. 进入项目目录 +cd ~/openclaw101/ + +# 2. 运行部署脚本 +chmod +x build-docker-run.sh +sudo ./build-docker-run.sh +``` + +脚本会自动: +- ✅ 检查 Docker 服务状态 +- ✅ 清理旧的构建缓存 +- ✅ 构建 Docker 镜像 +- ✅ 显示运行命令和访问地址 + +## 📋 脚本详解 + +### 脚本功能 +`build-docker-run.sh` 是一个自动化部署脚本,简化了 OpenClaw101 的容器化部署流程。 + +### 可配置参数 + +#### 1. 镜像标签(可选参数) +```bash +# 使用默认标签(openclaw101:latest) +./build-docker-run.sh + +# 使用自定义标签 +./build-docker-run.sh openclaw101:v1.0 +./build-docker-run.sh myregistry.com/openclaw101:production +``` + +#### 2. 容器名称和端口(在脚本中修改) +脚本默认使用以下配置: +```bash +容器名称:openclaw101 +主机端口:3000 +容器端口:80 +``` + +如果需要修改这些配置,可以编辑脚本中的运行命令部分: +```bash +# 在脚本中找到这一行(约第24行) +echo " docker run -d -p 3000:80 --name openclaw101 $TAG" + +# 修改为: +# docker run -d -p 8080:80 --name my-openclaw101 $TAG +``` + +### 配置示例 + +#### 示例1:使用不同端口 +```bash +# 修改脚本中的端口映射 +# 原配置:-p 3000:80 +# 新配置:-p 8080:80 + +# 然后运行脚本 +./build-docker-run.sh +``` + +#### 示例2:使用不同容器名称 +```bash +# 修改脚本中的容器名称 +# 原配置:--name openclaw101 +# 新配置:--name my-openclaw-app + +# 然后运行脚本 +./build-docker-run.sh +``` + +#### 示例3:同时修改端口和名称 +```bash +# 修改脚本中的运行命令 +# 原配置:docker run -d -p 3000:80 --name openclaw101 $TAG +# 新配置:docker run -d -p 9090:80 --name openclaw-prod $TAG + +# 然后运行脚本 +./build-docker-run.sh openclaw101:production +``` + +## 🔧 手动运行命令 + +如果你需要更多控制,也可以直接使用 Docker 命令: + +### 1. 构建镜像 +```bash +# 使用默认标签 +docker build -t openclaw101:latest . + +# 使用自定义标签 +docker build -t myregistry.com/openclaw101:v1.0 . +``` + +### 2. 运行容器 +```bash +# 基本运行(使用脚本默认配置) +docker run -d -p 3000:80 --name openclaw101 openclaw101:latest + +# 自定义端口 +docker run -d -p 8080:80 --name openclaw101 openclaw101:latest + +# 自定义容器名称 +docker run -d -p 3000:80 --name my-openclaw-app openclaw101:latest + +# 后台运行并自动重启 +docker run -d -p 3000:80 --name openclaw101 --restart unless-stopped openclaw101:latest +``` + +### 3. 查看运行状态 +```bash +# 查看容器状态 +docker ps | grep openclaw101 + +# 查看日志 +docker logs -f openclaw101 + +# 查看资源使用 +docker stats openclaw101 +``` + +## 🌐 访问应用 + +部署完成后,通过以下地址访问: + +``` +http://localhost:3000 +``` + +如果修改了端口,请使用对应的端口号: +``` +http://localhost:8080 # 如果修改为8080端口 +``` + +## 🛠️ 管理容器 + +### 停止容器 +```bash +docker stop openclaw101 +``` + +### 启动容器 +```bash +docker start openclaw101 +``` + +### 重启容器 +```bash +docker restart openclaw101 +``` + +### 删除容器 +```bash +# 停止并删除容器 +docker stop openclaw101 && docker rm openclaw101 + +# 删除镜像 +docker rmi openclaw101:latest +``` + +### 进入容器 +```bash +# 进入容器shell +docker exec -it openclaw101 sh +``` + +## 📊 脚本输出示例 + +运行 `./build-docker-run.sh` 会显示以下信息: + +``` +🔨 开始构建 OpenClaw101 Docker 镜像(修复版)... +📦 镜像标签: openclaw101:latest +🧹 清理旧的构建缓存... +📦 构建 Docker 镜像... + +✅ 构建完成! +📊 镜像信息: +openclaw101 latest abc123def456 35MB 2 minutes ago + +🚀 运行命令: + docker run -d -p 3000:80 --name openclaw101 openclaw101:latest + +🔍 查看日志: + docker logs -f openclaw101 + +🌐 访问地址: http://localhost:3000 +``` + +## ⚠️ 注意事项 + +1. **Docker 服务**:确保 Docker 服务正在运行 +2. **端口冲突**:如果 3000 端口被占用,请修改脚本中的端口配置 +3. **容器名称冲突**:如果已存在名为 `openclaw101` 的容器,请修改容器名称 +4. **权限问题**:通常不需要 `sudo`,除非 Docker 安装配置需要 +5. **构建缓存**:脚本会自动清理旧的构建缓存,但不会影响现有容器 + +## 🔄 更新部署 + +如果需要更新应用: + +```bash +# 1. 停止并删除旧容器 +docker stop openclaw101 && docker rm openclaw101 + +# 2. 重新构建和运行 +./build-docker-run.sh +``` + +## 📞 支持 + +如有问题,请参考: +- [Docker 官方文档](https://docs.docker.com/) +- [脚本源代码](./build-docker-run.sh) +- [项目主文档](./README.md) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..218e853 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +# ========================================== +# 阶段 1: 构建阶段 +# ========================================== +FROM node:20-alpine AS builder + +# 设置工作目录 +WORKDIR /app + +# 安装必要的构建工具(Alpine环境需要) +RUN apk add --no-cache libc6-compat + +# 先复制package文件(利用Docker缓存层) +COPY package*.json ./ + +# 安装所有依赖(包括开发依赖,构建需要TypeScript等) +RUN npm ci && npm cache clean --force + +# 复制源代码 +COPY . . + +# 验证 TypeScript 配置和路径别名 +# 如果这一步失败,会提前发现问题 +RUN echo "=== 验证 TypeScript 路径别名 ===" && \ + node -e "const ts = require('typescript'); const cfg = require('./tsconfig.json'); console.log('tsconfig paths:', JSON.stringify(cfg.compilerOptions?.paths, null, 2))" + +# 构建静态站点 +ENV NODE_ENV=production +RUN npm run build + +# ========================================== +# 阶段 2: 运行阶段(Nginx 托管) +# ========================================== +FROM nginx:1.25-alpine-slim AS runtime + +# 复制构建产物到 Nginx +COPY --from=builder /app/out /usr/share/nginx/html + +# 复制自定义 Nginx 配置 +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# 暴露端口 +EXPOSE 80 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/build-docker-run.sh b/build-docker-run.sh new file mode 100644 index 0000000..b1294a3 --- /dev/null +++ b/build-docker-run.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# OpenClaw101 Docker 构建脚本 +# 用法: ./build-docker-run.sh [tag] + +set -e + +# 默认标签 +TAG=${1:-"openclaw101:latest"} + +echo "🔨 开始构建 OpenClaw101 Docker 镜像..." +echo "📦 镜像标签: $TAG" + +# 检查 Docker 是否运行 +if ! docker info > /dev/null 2>&1; then + echo "❌ Docker 未运行,请启动 Docker 服务" + exit 1 +fi + +# 清理旧的构建缓存(可选) +echo "🧹 清理旧的构建缓存..." +docker builder prune -f + +# 构建镜像 +echo "📦 构建 Docker 镜像..." +docker build -t "$TAG" . + +# 显示构建结果 +echo "" +echo "✅ 构建完成!" +echo "📊 镜像信息:" +docker images | grep openclaw101 + +echo "" +echo "🚀 运行命令:" +echo " docker run -d -p 3000:80 --name openclaw101 $TAG" +echo "" +echo "🔍 查看日志:" +echo " docker logs -f openclaw101" +echo "" +echo "🌐 访问地址: http://localhost:3000" \ No newline at end of file diff --git a/next.config.js b/next.config.js index afa8e58..2caae56 100644 --- a/next.config.js +++ b/next.config.js @@ -1,3 +1,4 @@ +const path = require('path'); const withMDX = require('@next/mdx')({ extension: /\.mdx?$/, options: { @@ -13,6 +14,31 @@ const nextConfig = { unoptimized: true, }, pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'], + + // ========================================== + // 关键修复:配置 webpack 路径别名 + // 确保 @/* 路径在 Docker 环境中正确解析 + // ========================================== + webpack: (config) => { + // 确保 resolve 和 alias 对象存在 + if (!config.resolve) { + config.resolve = {}; + } + if (!config.resolve.alias) { + config.resolve.alias = {}; + } + + // 添加 @ 路径别名指向 src 目录 + config.resolve.alias['@'] = path.resolve(__dirname, 'src'); + + return config; + }, + + // 确保 TypeScript 路径别名也能被正确解析 + experimental: { + // 禁用某些可能导致问题的实验性功能 + turboMode: false, + }, }; module.exports = withMDX(nextConfig); diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..e00d4b5 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,26 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + # Gzip 压缩 + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml; + + # 缓存静态资源 + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Next.js 静态导出路由处理 + location / { + try_files $uri $uri.html $uri/ =404; + } + + # 404 页面 + error_page 404 /404.html; +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9bdc854..e6c3df3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -589,6 +589,7 @@ "resolved": "https://registry.npmjs.org/@mdx-js/loader/-/loader-3.1.1.tgz", "integrity": "sha512-0TTacJyZ9mDmY+VefuthVshaNIyCGZHJG2fMnGaDttCt8HmjUF7SizlHJpaCDoGnN635nK1wpzfpx/Xx5S4WnQ==", "license": "MIT", + "peer": true, "dependencies": { "@mdx-js/mdx": "^3.0.0", "source-map": "^0.7.0" @@ -648,6 +649,7 @@ "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", "license": "MIT", + "peer": true, "dependencies": { "@types/mdx": "^2.0.0" }, @@ -960,6 +962,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -992,6 +995,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1157,6 +1161,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2086,6 +2091,7 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -3465,6 +3471,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -3644,6 +3651,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -3656,6 +3664,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -4277,6 +4286,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" },