Willy
(Willy)
2026 年8 月 3 日 06:00
1
日志显示如下内容:
PG::InvalidTextRepresentation (ERROR: invalid input syntax for type inet: "unix:" LINE 7: client_ip = 'unix:', ^ ) lib/mini_sql_multisite_connection.rb:109:in 'MiniSqlMult
Job exception: ERROR: invalid input syntax for type inet: "unix:" LINE 2: SET ip_address = 'unix:' ^
发生此错误时,会显示一个**“Oops - Error 500”**页面。起初,我以为是 Caddy 的问题,因为它没有将客户端的 IP 地址转发给 Discourse,所以我尝试了多种不同的配置,但都没有解决问题。
值得一提的是,这种情况并不经常发生。它只是偶尔出现,而且当它发生时,只需刷新页面即可立即恢复网站。随后网站会正常运行相当长一段时间,直到错误再次随机出现。
我不是专家,而且我的自托管实例使用的是 Nginx 而不是 Caddy,但我能否请您提供 ./app/containers.yml 中实际的 Caddy 和 Discourse 模板配置?
您还记得在出错之前通常做了什么吗?我是说,更改管理员设置、发帖,还是使用了某些插件?
很抱歉无法为您的问题提供具体帮助,但我想您的回复能为您的问题增加价值,从而获得社区清晰快速的回应。
Falco
(Falco)
2026 年8 月 3 日 16:08
3
这意味着请求/用户有一个指向你的 Socket 的远程 IP,这表明你的代理链中的某些配置不正确。
Willy
(Willy)
2026 年8 月 3 日 20:47
4
@satonotdead @Falco
app.yml
templates:
- "templates/postgres.18.template.yml"
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.socketed.template.yml"
- "templates/enable-ruby-yjit.yml"
## 此容器应暴露哪些 TCP/IP 端口?
## 如果您希望 Discourse 与 Apache 或 nginx 等其他 Web 服务器共享端口,
## 请参阅 https://meta.discourse.org/t/17247 了解详情
expose:
# - "66:80" # http
# - "66:443" # https
params:
## 此容器应使用哪个 Git 版本?(默认:latest)
version: latest
## 最大上传大小(默认:10m)
upload_size: 150m
db_default_text_search_config: "pg_catalog.english"
## 将 db_shared_buffers 设置为总内存的 25%。
## 引导程序会根据检测到的 RAM 自动设置,或者您可以覆盖
db_shared_buffers: "2048MB"
## 可以提高排序性能,但会增加每个连接的内存使用量
#db_work_mem: "40MB"
## 此容器应使用哪个 Git 版本?(默认:tests-passed)
#version: tests-passed
env:
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
LANGUAGE: en_US.UTF-8
# DISCOURSE_DEFAULT_LOCALE: en
## https://meta.discourse.org/t/rescaling-the-server-which-configs-need-to-be-changed-unicorn-workers-memory-etc/252788
## 支持多少并发 Web 请求?取决于内存和 CPU 核心数。
## 引导程序会根据检测到的 CPU 自动设置,或者您可以覆盖
UNICORN_WORKERS: 8
## TODO:此 Discourse 实例响应的域名
## 必填。Discourse 无法使用裸 IP 地址运行。
DISCOURSE_HOSTNAME: example.com
## 如果您希望容器使用与上述指定的相同
## 主机名(-h 选项)启动,请取消注释(默认 "$hostname-$config")
#DOCKER_USE_HOSTNAME: true
## TODO:初始注册时将设为管理员和开发者的逗号分隔电子邮件列表
## 例如 'user1@example.com,user2@example.com'
DISCOURSE_DEVELOPER_EMAILS: 'admin+discourse@example.com'
## TODO:用于验证新账户和发送通知的 SMTP 邮件服务器
# SMTP 地址是必填项
# 警告:SMTP 密码应使用引号括起来以避免问题
DISCOURSE_SMTP_ADDRESS: smtp.provider.com
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: noreply@example.com
DISCOURSE_SMTP_PASSWORD: "***"
#DISCOURSE_SMTP_ENABLE_START_TLS: true # (可选,默认:true)
DISCOURSE_SMTP_DOMAIN: example.com # (某些提供商要求)
DISCOURSE_NOTIFICATION_EMAIL: noreply@example.com
#DISCOURSE_SMTP_OPENSSL_VERIFY_MODE: peer # (可选,默认:peer,有效值:none, peer, client_once, fail_if_no_peer_cert)
#DISCOURSE_SMTP_AUTHENTICATION: plain # (默认:plain,有效值:plain, login, cram_md5)
## 如果您添加了 Let's Encrypt 模板,请取消注释下方以获取免费 SSL 证书
# LETSENCRYPT_ACCOUNT_EMAIL: admin+letsencrypt@example.com
## 此 Discourse 实例的 http 或 https CDN 地址(配置为拉取)
## 请参阅 https://meta.discourse.org/t/14857 了解详情
#DISCOURSE_CDN_URL: https://discourse-cdn.example.com
## 用于 IP 地址查找的 MaxMind 地理位置 IP 账户 ID 和许可证密钥
## 请参阅 https://meta.discourse.org/t/-/173941 了解详情
#DISCOURSE_MAXMIND_ACCOUNT_ID: 123456
#DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456
# 强制 HTTPS
DISCOURSE_FORCE_HTTPS: true
# 请求限制
DISCOURSE_MAX_REQS_PER_IP_MODE: none
DISCOURSE_MAX_ADMIN_API_REQS_PER_MINUTE: 12000
DISCOURSE_MAX_DATA_EXPLORER_API_REQ_MODE: none
DISCOURSE_MAX_DATA_EXPLORER_API_REQS_PER_10_SECONDS: 1000
DISCOURSE_YJIT_ENABLED: true
## Docker 容器是无状态的;所有数据存储在 /shared 中
volumes:
- volume:
host: /var/discourse/shared/standalone
guest: /shared
- volume:
host: /var/discourse/shared/standalone/log/var-log
guest: /var/log
- volume:
host: /var/discourse/plugins
guest: /var/plugins
## 插件放在这里
## 请参阅 https://meta.discourse.org/t/19157 了解详情
hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone https://github.com/discourse/docker_manager.git
- cp -a /var/plugins/. $home/plugins/
## 构建后运行的任何自定义命令
run:
- exec: echo "Beginning of custom commands"
## 如果您想设置首次注册的“发件人”电子邮件地址,请取消注释并更改:
## 收到第一封注册电子邮件后,重新注释该行。它只需要运行一次。
#- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
- exec: echo "End of custom commands"
Caddyfile
#---------------------------------------------------------------------------------
{
storage file_system {
root /var/caddy/data
}
}
#---------------------------------------------------------------------------------
# 为了在 SSL 安全评分中获得 A+
(hsts) {
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
}
}
# 自托管 acme-dns 凭据
(tls-challenge) {
tls admin+letsencrypt@example.com {
dns acmedns {
username ***
password ***
subdomain ***
server_url http://acme.example.com:5005
}
}
}
#---------------------------------------------------------------------------------
# 论坛 (Discourse)
#---------------------------------------------------------------------------------
example.com {
#-------------------------------------------------------------------------------
import hsts
import tls-challenge
#-------------------------------------------------------------------------------
request_header X-Real-IP {remote_host}
reverse_proxy unix//var/discourse/shared/standalone/nginx.http.sock
#-------------------------------------------------------------------------------
}
#---------------------------------------------------------------------------------
# 子域名
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------
*.example.com {
#-------------------------------------------------------------------------------
import hsts
import tls-challenge
#-------------------------------------------------------------------------------
# 强制使用非 www 版本的域名
@www host www.example.com
redir @www https://example.com{uri} permanent
#-------------------------------------------------------------------------------
@store host store.example.com
handle @store {
@wc_private {
path /license.txt
path /readme.html
# 关键文件
path /wp-config.php
path /xmlrpc.php
path /wp-settings.php
path /wp-load.php
path /wp-blog-header.php
path /wp-admin.php
path /wp-admin/install.php
path /wp-content/uploads/wc-logs/*
path /wp-content/uploads/nuvei-logs/*
path /wp-content/uploads/woocommerce_uploads/*
}
# protect_php
@wc_private_php {
not path /wp-includes/ms-files.php
path_regexp protect_php ^/(wp-includes|wp-admin/includes|wp-content/uploads)/.*\.php$
}
respond @wc_private 403
respond @wc_private_php 403
root * /usr/share/wordpress
php_fastcgi unix//run/php/php8.3-fpm.sock
file_server
}
#-------------------------------------------------------------------------------
# 多个独立 HTML 文件
#-------------------------------------------------------------------------------
@join host join.example.com
handle @join {
root * /var/example/join
file_server
}
#-------------------------------------------------------------------------------
# 无匹配器
#-------------------------------------------------------------------------------
handle {
respond 404
}
#-------------------------------------------------------------------------------
}
更具体地说,此错误在前一个错误发生后几小时出现,并不经常发生。我在 app.yml 或 Caddyfile 中没有看到任何异常。
如果套接字连接在断开之前一直正常,我认为您可以添加显式的超时设置和传输选项。
嗯,正如我之前所说,我没有使用 Caddy,但你可以查看他们的官方文档 。
Willy
(Willy)
2026 年8 月 3 日 21:52
8
我想我找到问题了。如果我执行重建,我从不重启 Caddy。从现在开始,我会这样做:
./launcher rebuild app && systemctl reload caddy
我怀疑 Caddy 在重建后会使用 socket 缓存或类似的东西。但这通常不会在重建后立即发生。我们拭目以待。
Willy
(Willy)
2026 年8 月 4 日 17:32
9
我已经为此忙了好几天。我确认 Caddy 确实发送了该头部,nginx 也确实接收并应用了它;没有 CDN,没有其他进程触及 socket,也没有 webhook。所有测试都通过了。但 Unix 错误仍然不断出现。我原以为是因为重建导致的,但并非如此。所有这些问题都是在极长的时间内随机发生的。
现在 TCP 是我唯一的选项了吗?
你有没有把我建议的超时设置添加到你的 Caddy 模板中?虽然我不是专家,但我认为这可能会解决你的问题。
Willy
(Willy)
2026 年8 月 4 日 18:03
11
这样做没有意义,因为有些请求在15秒后失败,而另一些则在不到1秒内失败。这基本上毫无意义。
好的,你可以查看这两个链接:
HA!
I stand corrected: proxy_set_header X-Real-IP $remote_addr; is correct!
My problem was that i only refreshed my discourse tab instead of closing and opening a new one, and the connection was somehow kept by outer nginx.
After restarting nginx service: systemctl restart nginx, i can see the correct ips being passed to discourse.
@mpalmer can you confirm that what i did is ok, and if it is should i edit the guide/wiki and add this new header?
背景
Discourse 需要能够识别最终用户的真实 IP 地址。
然而,由于始终存在一个或多个上游 Web 服务器(运行在 Discourse 容器中的 nginx),最终用户从不直接连接到 Discourse。因此,我们需要一种以可信的方式将该信息传递给 Discourse 的方法。
x-forwarded-for 头信息就是解决方案。在本主题中,我将描述正确处理该信息的具体机制,以及我们期望它是如何传播的。
模板
用于信任上游代理的各种模板(例如 cloudflare.template.yml 或 fastly.template.yml)已更新为在 outlets 中使用可预测的文件名,而不是依赖文本替换(这种方式容易出错)。
文件名
server/real-ip-header.conf
此文件包含运行在容器中的 nginx 将用作真实来源的头信息,例如:
real_ip_header x-forwarded-for;
或者在 Cloudflare 模板中设置的:
real_ip_header cf-connecting-ip;
server/real-ip-re…
看来你缺少一个标头,或者你的 Discourse 模板文件中的信任链配置有问题。