反向代理
本文介绍如何通过 Nginx / Apache / Caddy 把 Markon 暴露到公网域名下。
访问控制
Markon 不内置任何身份认证。凡是能访问到该地址的人,均可读取工作区的全部内容;启用「共享标注」或「编辑」模式后,也具有写入能力。
把 Markon 挂到公网前,请先在网关层配好认证。 常见方案:
Basic Auth(nginx) — 在
proxy_pass之前加两行:nginxauth_basic "Markon"; auth_basic_user_file /etc/nginx/.htpasswd;完整示例见下方 Nginx 配置节。
OAuth2 代理 — 在 Markon 上游挂 oauth2-proxy,对接 GitHub / Google 等 IdP。
零信任隧道 — Cloudflare Access、Tailscale Funnel;流量在到达服务器之前已完成身份核验。
网络层隔离 — Tailscale、WireGuard,或绑定
--host 127.0.0.1仅本机访问,适合单人私有部署。
如需对外提供只读访问,目前须在代理层屏蔽写入方法(PUT/POST/DELETE),应用层暂无原生只读公开模式。
为什么需要反向代理
- 绑定域名 — 用
docs.example.com替代http://192.168.1.5:6419 - HTTPS — 通过代理层终止 TLS
- 统一入口 — 多个内部服务共用 80/443 端口
Markon 侧配置
让 Markon 只监听本地,由代理转发:
bash
markon --host 127.0.0.1 -p 6419 \
-b https://docs.example.com \
--qr https://docs.example.com \
--enable-search \
--shared-annotation关键点:
--host 127.0.0.1— 仅本地访问,安全-b https://docs.example.com— 启动后浏览器打开公网 URL(不传 BASE 则只开本地地址)--qr https://docs.example.com(--entry别名)— 终端二维码与日志中的「accessible at」用公网 URL;不设这条会回落到内网 IP
Nginx
nginx
server {
listen 443 ssl http2;
server_name docs.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
proxy_pass http://127.0.0.1:6419;
proxy_http_version 1.1;
# WebSocket 支持(共享标注需要)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 透传请求头
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;
# WebSocket 长连接保活
proxy_read_timeout 86400;
}
}Apache
启用模块:
bash
sudo a2enmod proxy proxy_http proxy_wstunnel rewrite sslVirtualHost 配置:
apache
<VirtualHost *:443>
ServerName docs.example.com
SSLEngine on
SSLCertificateFile /path/to/fullchain.pem
SSLCertificateKeyFile /path/to/privkey.pem
# WebSocket (共享标注)
RewriteEngine on
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://127.0.0.1:6419/$1" [P,L]
ProxyPass / http://127.0.0.1:6419/
ProxyPassReverse / http://127.0.0.1:6419/
</VirtualHost>Caddy
最简配置:
caddyfile
docs.example.com {
reverse_proxy 127.0.0.1:6419
}Caddy 自动处理 HTTPS(Let's Encrypt)和 WebSocket,无需额外配置。
Systemd 服务
把 Markon 托管为系统服务,开机自启:
ini
# /etc/systemd/system/markon.service
[Unit]
Description=Markon Markdown Renderer
After=network.target
[Service]
Type=simple
User=markon
WorkingDirectory=/srv/docs
ExecStart=/usr/local/bin/markon \
--host 127.0.0.1 -p 6419 \
--enable-search --shared-annotation \
-b https://docs.example.com \
--qr https://docs.example.com
Restart=on-failure
Environment="MARKON_SQLITE_PATH=/var/lib/markon/annotation.sqlite"
[Install]
WantedBy=multi-user.target启用:
bash
sudo systemctl enable --now markon系统路径前缀
Markon 使用 /_/ 作为内部资源的保留前缀(CSS、JS、WebSocket)。在反向代理时:
✅ 可以正常代理:不需要特殊配置 ❌ 不要在工作区根目录创建名为 _ 的文件夹(单下划线)
注意只有精确的 /_/ 会冲突,_build/、__pycache__/ 等不受影响。
故障排查
WebSocket 连不上
- 确认代理配置中加了
Upgrade和Connection: upgrade头 - Nginx 需要
proxy_read_timeout够长(默认 60s 会断线)
QR 码打开的是内网 IP
- 检查
--qr参数是否传了正确的公网 URL
浏览器打开空白
- 检查 Markon 进程是否真的在跑:
curl http://127.0.0.1:6419 - 检查代理错误日志:Nginx 是
/var/log/nginx/error.log