最稳妥方式是用docker部署excalidraw官方镜像ghcr.io/excalidraw/excalidraw:latest,需先确保docker正常运行,再执行docker pull和docker run -d --name excalidraw -p 3002:80 -e node_env=production --restart=unless-stopped命令启动容器,访问http://localhost:3002即可使用。

直接用 Docker 部署是最稳妥、最省事的方式,不需要碰 Node.js、Yarn 或构建流程,镜像已预编译好,拉下来就能跑。
确认 Docker 已安装且正常运行
Excalidraw 官方镜像依赖 Docker 运行时,不是可选,是硬性前提。常见卡点是:
-
docker: command not found:说明 Docker 没装,或没加到$PATH;Ubuntu/Debian 请按官方源安装,别用 snap 版本(有权限和 cgroup 问题) -
Cannot connect to the Docker daemon:Docker 服务没启动,执行sudo systemctl start docker并确认用户在docker组里(sudo usermod -aG docker $USER,然后重新登录终端) - 拉镜像超时或失败:国内网络常因 registry 访问慢导致,需配置镜像加速器——编辑
/etc/docker/daemon.json,加入"registry-mirrors"字段(如"https://docker.mirrors.ustc.edu.cn"),再sudo systemctl restart docker
拉取并运行官方镜像(推荐 ghcr.io)
Excalidraw 官方主镜像已从 excalidraw/excalidraw 迁移到 GitHub Container Registry,旧镜像可能不再更新。务必用新地址:
执行:docker pull ghcr.io/excalidraw/excalidraw:latest
然后启动容器:docker run -d --name excalidraw -p 3002:80 -e NODE_ENV=production --restart=unless-stopped ghcr.io/excalidraw/excalidraw:latest
注意几个关键点:
- 端口映射用
-p 3002:80,避免和 nginx/apache 冲突(别硬写80,除非你停掉其他服务) -
NODE_ENV=production环境变量必须显式设置,否则前端会加载开发模式资源(比如未压缩 JS、热更新脚本),影响性能和安全性 -
--restart=unless-stopped是生产必需项,否则机器重启后服务就挂了
验证服务是否可用 & 常见访问失败原因
容器启动后,访问 http://:3002 应该看到白板界面。如果打不开,先查三件事:
- 执行
docker logs excalidraw,看有没有Server listening on port 80类似输出;若报错EADDRINUSE,说明容器内端口被占(极少见),换镜像重试 - 执行
curl -I http://localhost:3002,本地能通但外网不通 → 检查云服务商安全组(放行 TCP 3002)、服务器防火墙(sudo ufw allow 3002或sudo iptables -L) - 浏览器显示空白或 404 → 多半是路径问题:确保 URL 末尾**没有斜杠**(
http://ip:3002/会 404,http://ip:3002才对),这是静态资源路由的限制
需要协作?得额外起 room 服务
只跑 ghcr.io/excalidraw/excalidraw 镜像,你只能单机使用(数据存在浏览器 localStorage)。要多人实时协作,必须部署配套的 excalidraw-room 后端服务。
它不包含在前端镜像里,得单独起一个容器:
docker run -d --name excalidraw-room -p 3003:3000 -e EXCALIDRAW_ROOM_URL=http://your-server-ip:3002 -e NODE_ENV=production --restart=unless-stopped ghcr.io/excalidraw/room:latest
然后在前端页面右上角点击「Share」→「Create room」时,它才会连接到这个 3003 端口。注意:
-
EXCALIDRAW_ROOM_URL必须填**外网可访问的地址**(比如https://draw.example.com),不能写localhost或内网 IP,否则协作链接无法被其他人访问 - 生产环境强烈建议用 Nginx 反向代理 + HTTPS,否则浏览器会阻止混合内容(HTTP 页面连 WebSocket 的 wss:// 是强制要求)
- room 服务本身无持久化,断电即丢房间状态,这不是 bug,是设计使然——它只做消息中转,不存图
真正容易被忽略的是协作链路的闭环:前端页面、room 服务、反向代理、DNS 解析、HTTPS 证书,五者缺一不可。很多人卡在“点了 Share 没反应”,其实只是 room 地址填错了,或者浏览器控制台报了 WebSocket connection to 'ws://...' failed —— 这时候别急着改代码,先检查 network tab 里 ws 请求发到了哪个地址,再比对 room 容器实际监听的地址是否匹配。











