Использую Unix-сокет между Caddy и Discourse вместо TCP, но время от времени получаю ошибку «unix:»

Логи показывают следующее:

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, поэтому я попробовал несколько различных конфигураций, но ни одна из них не решила проблему.

Стоит отметить, что это происходит нечасто. Ошибка возникает лишь изредка, и в таких случаях достаточно просто обновить страницу, чтобы сайт снова заработал. Затем он функционирует нормально довольно долго, прежде чем ошибка случайно появится снова.

Я не эксперт и использовал не Caddy, а Nginx на своём самохостинге, но могу ли я попросить у вас вашу фактическую конфигурацию шаблонов Caddy и Discourse в ./app/containers.yml?

Помните ли вы, что вы обычно делали перед возникновением ошибки? Я имею в виду, изменение настроек администратора, публикация, использование какого-либо плагина?

Извините, что не могу дать конкретную помощь по вашей проблеме, но я думаю, что ваши ответы могут добавить ценности к вашему вопросу для получения чёткого и быстрого ответа от сообщества.

Это означает, что у запроса/пользователя есть удалённый IP-адрес, указывающий на ваш сокет, что свидетельствует о неправильной конфигурации чего-то в вашей цепочке прокси.

@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,
## ознакомьтесь с подробностями по ссылке 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% от общей памяти.
  ## будет установлено автоматически при инициализации на основе обнаруженной оперативной памяти, или вы можете переопределить
  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
  ## Сколько одновременных веб-запросов поддерживается? Зависит от оперативной памяти и ядер процессора.
  ## будет установлено автоматически при инициализации на основе обнаруженных процессоров, или вы можете переопределить
  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 ADDRESS обязателен
  # ВНИМАНИЕ: пароль 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)

  ## Если вы добавили шаблон Lets Encrypt, раскомментируйте ниже, чтобы получить бесплатный SSL-сертификат
  # LETSENCRYPT_ACCOUNT_EMAIL: admin+letsencrypt@example.com

  ## Адрес CDN (http или https) для этого экземпляра Discourse (настроен на получение данных)
  ## ознакомьтесь с подробностями по ссылке https://meta.discourse.org/t/14857
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com

  ## ID аккаунта и лицензионный ключ Maxmind для геолокации по IP-адресам
  ## ознакомьтесь с подробностями по ссылке 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
	}
}

#---------------------------------------------------------------------------------

# Для получения оценки A+ по безопасности SSL
(hsts) {
	header {
		Strict-Transport-Security "max-age=31536000; includeSubDomains"
	}
}

# учетные данные self-hosted 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, но вы можете ознакомиться с официальной документацией.

Думаю, я нашёл проблему. Если я выполняю пересборку, я никогда не перезапускаю Caddy. С этого момента я буду делать так:

./launcher rebuild app && systemctl reload caddy

Я подозреваю, что Caddy использует кэш сокета или что-то подобное после пересборки. Но обычно это не происходит сразу после пересборки. Посмотрим.