SSL_connect вернул=1 errno=0 peeraddr=162.243.189.2:443 state=error: проверка сертификата не удалась (несоответствие имени хоста)

У меня закончилось место на Digital Ocean Droplet, поэтому я решил перенести загруженные файлы в Digital Ocean Space.

Вот что я настроил…

  • s3 access key id — скопирован из DO CP > API > Applications & API

  • s3 secret access key — скопирован из DO CP > API > Applications & API

  • s3 region — не уверен, что это важно для DO Spaces, но оставил значение по умолчанию — US East (N. Virginia)

  • s3 upload bucket — неясно, нужно ли создавать папку в Space. Я пробовал оба варианта…

    • uploads — папка в Space ещё не создана
    • files — папка в Space уже создана
  • s3 endpoint — здесь, думаю, моя ошибка. Я пробовал следующие версии с https://…

Я видел это…

…и это…

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

Я также видел это…

…но в админ-панели нельзя оставить поле “s3 upload bucket” пустым, поэтому я не уверен, связано ли это с моей проблемой. К тому же это, похоже, актуально только при использовании AWS S3. Я пробовал создать папку в DO Space и указать её имя. Также пробовал имя несуществующей папки, на случай если система должна создать её сама. Ничего не помогло.

Ещё я видел это…

…но я далеко не эксперт, поэтому решил не лезть туда.

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

Буду очень признателен за любую помощь. Спасибо.

Также я пробовал использовать учетные данные API DigitalOcean в виде:

Не уверен, с чем именно они должны совпадать, поэтому здесь я тоже немного запутался.

Нет, это не так. Хотя вы можете настроить конечные точки S3 в интерфейсе, мы тестировали и проверяли работу только с клонами S3, такими как предложение Digital Ocean, при настройке в файле app.yml.

Вики-страница Настройка совместимого с S3 провайдера объектного хранилища для загрузок была создана благодаря усилиям многих людей, поэтому я рекомендую придерживаться её рекомендаций.

Что ж, Фалько меня опередил, но вот что я хотел сказать…

Нет. Вам нужно следовать инструкции Configure an S3 compatible object storage provider for uploads и добавить настройки в ваш файл app.yml.

Вам нужен настоящий CDN, например bunny.net. Я не думаю, что Cloudflare справится с этой задачей.

Спасибо.

Я не вижу раздела DISCOURSE_S3 в файле app.yml. Нужно ли мне просто создать отдельную строку для каждого параметра? Или это уже делается с помощью команд sudo?

Мне не совсем понятно, где именно выполнять эти команды sudo или куда их помещать. Неясно, является ли это разовой командой для добавления настроек или же это что-то, что должно быть указано в app.yml, чтобы учитываться постоянно.

Команды sudo нужно добавлять в раздел app.yml или только строки с настройками DISCOURSE_S3?


Можно ли оставить поле DISCOURSE_S3_REGION пустым при использовании DO Spaces?


Обязательно ли наличие CDN? У нас очень низкий трафик и небольшая группа пользователей. Я стараюсь по возможности минимизировать количество компонентов системы.

Это…

…размещается ниже # plugins to here в разделе…

hooks:

…после секции…

after_code?

OK. Я добавил after_assets_precompile…

Я пересобрал проект, но всё ещё не вижу секции S3.

Мне просто нужно создать её?
Влияет ли то, где я размещу настройки?

Как сказано в руководстве, они должны находиться в разделе env: вместе с другими настройками, начинающимися на DISCOURSE_:

Есть ли какое-либо решение для этой проблемы? Я получаю ту же ошибку при попытке использовать Oracle Cloud Storage.

Я следовал руководству wiki, настроив параметры в app.yml. Я также вручную проверил подключение с помощью s3cmd, и оно было верным. Однако при загрузке изображения в посте я получил то же сообщение об ошибке.

Сообщение (4 копии)
Исключение задачи: SSL_connect returned=1 errno=0 peeraddr=134.70.128.1:443 state=error: ошибка проверки сертификата (несоответствие имени хоста)
Трассировка стека
/usr/local/lib/ruby/3.2.0/net/protocol.rb:46:in `connect_nonblock'
/usr/local/lib/ruby/3.2.0/net/protocol.rb:46:in `ssl_socket_connect'
/usr/local/lib/ruby/3.2.0/net/http.rb:1342:in `connect'
/usr/local/lib/ruby/3.2.0/net/http.rb:1248:in `do_start'
/usr/local/lib/ruby/3.2.0/net/http.rb:1243:in `start'
/usr/local/lib/ruby/3.2.0/delegate.rb:87:in `method_missing'
aws-sdk-core-3.130.2/lib/seahorse/client/net_http/connection_pool.rb:307:in `start_session' 
aws-sdk-core-3.130.2/lib/seahorse/client/net_http/connection_pool.rb:100:in `session_for' 
aws-sdk-core-3.130.2/lib/seahorse/client/net_http/handler.rb:128:in `session' 
aws-sdk-core-3.130.2/lib/seahorse/client/net_http/handler.rb:76:in `transmit' 
aws-sdk-core-3.130.2/lib/seahorse/client/net_http/handler.rb:50:in `call' 
aws-sdk-core-3.130.2/lib/seahorse/client/plugins/content_length.rb:24:in `call' 
aws-sdk-core-3.130.2/lib/seahorse/client/plugins/request_callback.rb:85:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/s3_signer.rb:132:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/s3_signer.rb:63:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/s3_host_id.rb:17:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/xml/error_handler.rb:10:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/transfer_encoding.rb:26:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/helpful_socket_errors.rb:12:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/s3_signer.rb:110:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/redirects.rb:20:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/retry_errors.rb:360:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/retry_errors.rb:394:in `retry_request' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/retry_errors.rb:382:in `retry_if_possible' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/retry_errors.rb:371:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/retry_errors.rb:394:in `retry_request' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/retry_errors.rb:382:in `retry_if_possible' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/retry_errors.rb:371:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/retry_errors.rb:394:in `retry_request' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/retry_errors.rb:382:in `retry_if_possible' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/retry_errors.rb:371:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/http_checksum.rb:19:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/endpoint_pattern.rb:30:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/accelerate.rb:67:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/checksum_algorithm.rb:136:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/bucket_dns.rb:35:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/dualstack.rb:41:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/expect_100_continue.rb:22:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/bucket_name_restrictions.rb:26:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/arn.rb:62:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/rest/handler.rb:10:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/recursion_detection.rb:18:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/user_agent.rb:13:in `call' 
aws-sdk-core-3.130.2/lib/seahorse/client/plugins/endpoint.rb:47:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/param_validator.rb:26:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/arn.rb:88:in `call' 
aws-sdk-core-3.130.2/lib/seahorse/client/plugins/raise_response_errors.rb:16:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/sse_cpk.rb:24:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/dualstack.rb:27:in `call' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/accelerate.rb:56:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/checksum_algorithm.rb:111:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/jsonvalue_converter.rb:22:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/idempotency_token.rb:19:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/param_converter.rb:26:in `call' 
aws-sdk-core-3.130.2/lib/seahorse/client/plugins/request_callback.rb:71:in `call' 
aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/response_paging.rb:12:in `call' 
aws-sdk-core-3.130.2/lib/seahorse/client/plugins/response_target.rb:24:in `call' 
aws-sdk-core-3.130.2/lib/seahorse/client/request.rb:72:in `send_request' 
aws-sdk-s3-1.114.0/lib/aws-sdk-s3/client.rb:10921:in `put_bucket_policy' 
/var/www/discourse/lib/s3_inventory.rb:183:in `update_bucket_policy' 
/var/www/discourse/app/jobs/regular/update_s3_inventory.rb:16:in `block in execute' 
/var/www/discourse/app/jobs/regular/update_s3_inventory.rb:14:in `each' 
/var/www/discourse/app/jobs/regular/update_s3_inventory.rb:14:in `execute' 
/var/www/discourse/app/jobs/base.rb:292:in `block (2 levels) in perform' 
rails_multisite-5.0.0/lib/rails_multisite/connection_management.rb:82:in `with_connection'
/var/www/discourse/app/jobs/base.rb:279:in `block in perform' 
/var/www/discourse/app/jobs/base.rb:275:in `each' 
/var/www/discourse/app/jobs/base.rb:275:in `perform' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:202:in `execute_job' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:170:in `block (2 levels) in process' 
sidekiq-6.5.12/lib/sidekiq/middleware/chain.rb:177:in `block in invoke' 
/var/www/discourse/lib/sidekiq/pausable.rb:134:in `call' 
sidekiq-6.5.12/lib/sidekiq/middleware/chain.rb:179:in `block in invoke' 
sidekiq-6.5.12/lib/sidekiq/middleware/chain.rb:182:in `invoke' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:169:in `block in process' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:136:in `block (6 levels) in dispatch' 
sidekiq-6.5.12/lib/sidekiq/job_retry.rb:113:in `local' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:135:in `block (5 levels) in dispatch' 
sidekiq-6.5.12/lib/sidekiq.rb:44:in `block in <module:Sidekiq>' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:131:in `block (4 levels) in dispatch' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:263:in `stats' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:126:in `block (3 levels) in dispatch' 
sidekiq-6.5.12/lib/sidekiq/job_logger.rb:13:in `call' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:125:in `block (2 levels) in dispatch' 
sidekiq-6.5.12/lib/sidekiq/job_retry.rb:80:in `global' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:124:in `block in dispatch' 
sidekiq-6.5.12/lib/sidekiq/job_logger.rb:39:in `prepare' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:123:in `dispatch' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:168:in `process' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:78:in `process_one' 
sidekiq-6.5.12/lib/sidekiq/processor.rb:68:in `run' 
sidekiq-6.5.12/lib/sidekiq/component.rb:8:in `watchdog' 
sidekiq-6.5.12/lib/sidekiq/component.rb:17:in `block in safe_thread' 

Заранее спасибо!

PS. Проблема возникает не только с Oracle Cloud Service, но и с другими отечественными провайдерами услуг.

Возможно, вы обращаетесь к бакету с неправильным именем?

Какого провайдера бакетов вы используете?

Как я упоминал выше: я пытаюсь использовать Oracle Cloud Storage. Я также проверил это вручную с помощью инструмента s3cmd с тем же аккаунтом.

Ошибиться в имени невозможно, так как я просто скопировал и вставил его.

Я проверил DNS-запись конечной точки S3:

dig axhjdarc4cuy.compat.objectstorage.ap-singapore-1.oraclecloud.com

; <<>> DiG 9.18.18-0ubuntu0.22.04.1-Ubuntu <<>> axhjdarc4cuy.compat.objectstorage.ap-singapore-1.oraclecloud.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63008
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;axhjdarc4cuy.compat.objectstorage.ap-singapore-1.oraclecloud.com. IN A

;; ANSWER SECTION:
axhjdarc4cuy.compat.objectstorage.ap-singapore-1.oraclecloud.com. 258 IN CNAME compat.objectstorage.ap-singapore-1.oci.oraclecloud.com.
compat.objectstorage.ap-singapore-1.oci.oraclecloud.com. 258 IN	CNAME objectstorage.ap-singapore-1.oci.oraclecloud.com.
objectstorage.ap-singapore-1.oci.oraclecloud.com. 174 IN A 134.70.128.1

;; AUTHORITY SECTION:
ap-singapore-1.oci.oraclecloud.com. 258	IN SOA	ns1.p200.dns.oraclecloud.net. hostmaster.ap-singapore-1.oci.oraclecloud.com. 682052 3600 900 31536000 1800

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Sat Nov 04 18:58:03 +07 2023
;; MSG SIZE  rcvd: 252

Затем я использовал целевой адрес: objectstorage.ap-singapore-1.oci.oraclecloud.com вместо исходного имени: axhjdarc4cuy.compat.objectstorage.ap-singapore-1.oraclecloud.com.

В результате в инструменте s3cmd я получил точно такое же сообщение об ошибке, как и в Discourse:

Пожалуйста, подождите, выполняется попытка перечислить все бакеты...
ОШИБКА: Тест не удался: [SSL: CERTIFICATE_VERIFY_FAILED] ошибка проверки сертификата: несоответствие имени хоста, сертификат не действителен для 'objectstorage.ap-singapore-1.oci.oraclecloud.com'. (_ssl.c:1007)

У меня нет опыта решения подобных проблем. :frowning:

Так что, возможно, проблема в следующем:

Есть ли способ исправить эту проблему? Спасибо!

Используйте имя, соответствующее сертификату.

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

Моя конечная точка: .compat.objectstorage..oraclecloud.com
CN сертификата: *.compat.objectstorage..oraclecloud.com

Я смог подключиться с помощью инструмента s3cmd. Однако не удалось настроить загрузку S3 для Discourse с той же конфигурацией.

Сообщение об ошибке: SSL_connect returned=1 errno=0 peeraddr=134.70.128.1:443 state=error: certificate verify failed (Hostname mismatch)

Я хочу попробовать другой способ, настроив это в среде Ruby (после поиска везде):

OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

Но как это можно настроить в Discourse? Пожалуйста!

Это плохая идея, так как это подорвет многие защиты, которые обеспечивают X509-сертификаты.

Можете показать ваши настройки, не содержащие секреты, здесь? Обратите внимание, что Oracle Cloud не поддерживается, но мы всё же быстро посмотрим, нет ли чего-то явно неверного.

Да, вы правы, когда отключаете это. Я просто хочу найти причину, чтобы создать PR, если это ошибка в библиотеке Ruby.

Мои настройки очень простые: я просто пытаюсь загружать изображения в хранилище, совместимое с S3.

  DISCOURSE_USE_S3: true
  DISCOURSE_S3_REGION: <region>
  DISCOURSE_S3_ENDPOINT: https://<namespace>.compat.objectstorage.<region>.oraclecloud.com
  DISCOURSE_S3_ACCESS_KEY_ID: <access_key_id>
  DISCOURSE_S3_SECRET_ACCESS_KEY: <access_key>
  DISCOURSE_S3_BUCKET: <bucket_name>

В Oracle Cloud Storage есть определённый формат для адреса конечной точки. Но какой бы формат я ни пробовал, возникала одна и та же ошибка, которую я показал выше:

SSL_connect returned=1 errno=0 peeraddr=134.70.128.1:443 state=error: certificate verify failed (Hostname mismatch)

В приведённом выше формате я проверил сертификат, и на мой взгляд, всё в порядке:

Как я уже говорил ранее, я использовал эти настройки для подключения через инструмент s3cmd, и всё работало нормально. Большое спасибо!

Хорошо, я добавил binding.pry в начало метода ssl_socket_connect, и вот что я вижу при попытке использовать эти настройки:

→ DISCOURSE_USE_S3=true DISCOURSE_S3_REGION=ap-singapore-1 DISCOURSE_S3_ENDPOINT=https://axhjdarc4cuy.compat.objectstorage.ap-singapore-1.oraclecloud.com DISCOURSE_S3_ACCESS_KEY_ID=foo DISCOURSE_S3_SECRET_ACCESS_KEY=bar DISCOURSE_S3_BUCKET=bucketname bin/rails c
Загрузка окружения разработки (Rails 7.0.7)
[1] pry(main)> s3 = S3Helper.build_from_config; s3.list

Из: /home/michael/.rvm/gems/ruby-3.2.2@discourse/gems/net-protocol-0.2.2/lib/net/protocol.rb:42 Net::Protocol#ssl_socket_connect:

    40: def ssl_socket_connect(s, timeout)
    41:   binding.pry
 => 42:   if timeout
    43:     while true
    44:       raise Net::OpenTimeout if timeout <= 0
    45:       start = Process.clock_gettime Process::CLOCK_MONOTONIC
    46:       # to_io требуется, так как у SSLSocket пока нет wait_readable
    47:       case s.connect_nonblock(exception: false)
    48:       when :wait_readable; s.to_io.wait_readable(timeout)
    49:       when :wait_writable; s.to_io.wait_writable(timeout)
    50:       else; break
    51:       end
    52:       timeout -= Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
    53:     end
    54:   else
    55:     s.connect
    56:   end
    57: end

[1] pry(#<Net::HTTP>)> s.hostname
=> "bucketname.axhjdarc4cuy.compat.objectstorage.ap-singapore-1.oraclecloud.com"

Таким образом, фактическое имя хоста, к которому происходит подключение, — bucketname.axhjdarc4cuy.compat.objectstorage.ap-singapore-1.oraclecloud.com, что не совпадает с *.compat.objectstorage.ap-singapore-1.oraclecloud.com, поэтому ошибка корректна.

К сожалению, OCI не поддерживает такой стиль доступа:

Используйте доступ на основе пути в вашем приложении. Доступ в стиле виртуального хоста (обращение к бакету как {bucketnamespace}.compat.objectstorage.{region}.oraclecloud.com [sic]) не поддерживается.

С другой стороны, Discourse поддерживает только доступ в стиле виртуального хоста ({bucketname}.{namespace}.compat.objectstorage.{region}.oraclecloud.com.).

Мы убрали настройку, которая могла бы сделать это возможным, некоторое время назад, так как она не была хорошо поддержана (см. сообщение коммита).

Заставить это работать будет непросто и потребует сложной разработки и тестирования для добавления этой поддержки.

Здесь обитают драконы.

(xref: S3 Path Style Access)

Очень ясно объясняет. Большое спасибо!

Спасибо, но я так и не разобрался.

Нашёл, о чём он говорил, но при копировании и вставке текста регистр букв инвертируется. Я сдался и больше к этому не возвращался. Возможно, попробую снова в следующем году.

Я надеялся, что кто-нибудь к тому времени разберётся и лучше опишет настройку, чтобы она соответствовала моим планам.

В любом случае спасибо.

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