Cloudflare WorkersでDeepL APIを呼び出すとError 525になる理由と回避策

contents 8
  1. 01 はじめに
  2. 02 Error 525とは何か
  3. 03 発生するコード例
  4. 04 原因の考察
  5. 05 解決策
  6. 06 運用上の留意点
  7. 07 まとめ
  8. 08 参考文献

はじめに

Cloudflare Workersは、エッジに分散配置された軽量なサーバーレス環境として、多くの開発者に利用されています。リクエスト処理をエッジ側で完結させることで、レイテンシ削減やスケーラビリティ向上を実現できる点は大きな魅力です。ところが、外部のAPIと連携しようとした際に、思わぬ落とし穴に遭遇する場合があります。

特にDeepL APIとの連携において「Error 525: SSL handshake failed」というエラーが発生する事例は、一定数の開発者を悩ませています。ローカル環境では正常に動作するにもかかわらず、Cloudflare Workersにデプロイした途端に失敗する現象は不可解に見えます。本稿では、このエラーの背景を丁寧に整理し、実運用における現実的な回避策を提示します。

Error 525とは何か

Error 525は、CloudflareにおけるSSLハンドシェイクの失敗を意味します。一般的には、Cloudflareがオリジンサーバーに接続しようとした際にTLS/SSLのネゴシエーションが成立しなかった場合に返されます。しかし、今回のケースでは「オリジン=DeepL API」という位置づけになるため、WorkersからDeepLへの直接的なTLS接続が失敗していることを意味します。

通常のWebブラウザやNode.js環境で同じコードを実行すると問題なくDeepLと通信できます。したがって、問題はCloudflare Workersの実行環境におけるTLS実装の仕様と、DeepL APIが期待する暗号スイートや証明書設定の間に不整合があると推測されます。

発生するコード例

以下のように、Cloudflare Workers内でDeepL APIにリクエストを送信すると525エラーが発生します。

export default {
  async fetch(request, env) {
    const response = await fetch('https://api-free.deepl.com/v2/translate', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': `DeepL-Auth-Key ${env.DEEPL_API_KEY}`,
      },
      body: new URLSearchParams({
        text: 'Hello, world!',
        target_lang: 'DE',
      }),
    });

    if (!response.ok) {
      return new Response(`DeepL API error: ${response.status} ${response.statusText}`);
    }
    return response;
  }
}

このコードはNode.js環境では正常に翻訳結果を返します。しかし、Workers上で実行すると必ず525エラーとなり、レスポンスが返ってきません。

原因の考察

なぜこの問題が発生するのでしょうか。公開されている情報やGitHubのIssue報告をもとにすると、以下の要因が関与している可能性があります。

  • TLSバージョンの不一致: Workers(workerd)の制約により、DeepL側が期待する暗号スイート/設定と不整合を起こす可能性。
  • SNIの取り扱い差: エッジランタイム特有のSNI拡張挙動差により、証明書検証が失敗するケース。
  • 証明書チェーン検証: ルート証明書ストア差異により、DeepLの証明書検証が失敗する可能性。

これらのいずれもCloudflare側で改善されるべき性質の問題であり、ユーザー側が直接制御することはできません。類似の報告が複数挙がっており、現時点では「既知の未解決問題」と見なされています。

解決策

現時点での実運用における解決策は、大きく分けて2つです。

1. 中継サーバーを利用する

Workersから直接DeepL APIに接続する代わりに、中継サーバーを用意して間接的にリクエストを転送する方法です。中継サーバーは一般的なNode.js環境や他のクラウド基盤で稼働させれば、DeepLとの通信は正常に行えます。

以下はExpressで実装した簡易的な例です。

import express from 'express';
import fetch from 'node-fetch';

const app = express();
app.use(express.json());

app.post('/translate', async (req, res) => {
  const deeplRes = await fetch('https://api-free.deepl.com/v2/translate', {
    method: 'POST',
    headers: {
      'Authorization': `DeepL-Auth-Key ${process.env.DEEPL_API_KEY}`,
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams(req.body),
  });

  const data = await deeplRes.json();
  res.json(data);
});

app.listen(3000, () => console.log('Proxy server running on port 3000'));

Workersからはこの中継サーバーにリクエストを送ることで、間接的にDeepL APIを利用できます。セキュリティ上の観点から、認証やCORS制御を必ず導入すべきです。

2. 代替のサーバーレス環境を利用する

Workers特有の問題を避けるため、AWS LambdaやGoogle Cloud Functionsなど、別のサーバーレス基盤に処理を移すことも選択肢となります。これらの環境では一般的なTLSライブラリを利用しているため、DeepLとの接続に失敗することはほぼありません。

特に既存のバックエンド基盤をすでに運用している場合は、翻訳処理のみをそちらにオフロードする設計が合理的です。

運用上の留意点

  • コストの増加: 中継に伴いレイテンシや運用コストが増加。利用頻度とコストのバランス検討が必要。
  • セキュリティ対策: APIキーは中継側に置くため、認証・レート制限・監査ログ等のアクセス制御が必須。
  • 将来的な改善期待: WorkersのTLS実装改善により直接DeepLと通信できる可能性。公式情報やIssue更新をウォッチ。

まとめ

Cloudflare WorkersとDeepL APIの組み合わせにおける「Error 525: SSL handshake failed」は、現在も未解決の技術的制約に由来する既知の問題です。根本的な解決はCloudflare側の改善を待つほかありませんが、中継サーバーを用いるか、代替のサーバーレス環境に処理を移すことで回避可能です。なるほど、というよりは「よくある落とし穴」と整理しておくのが適切でしょう。

エッジ環境の利用は強力ですが、暗号化通信の仕様差異が予期せぬ障害を生むこともあります。設計段階でこれらの制約を踏まえ、柔軟に回避策を組み込むことが健全な運用につながります。

参考文献

share Twitter Facebook