curl・HTTPクライアントで「SSL certificate problem: self-signed certificate」エラーを修正する

beginner🔒 SSL/TLS2026-03-29| Linux、macOS、Windows — curl、Python requests、Node.js、Git、wget、自己署名TLS証明書を使用するサーバーに接続するすべてのHTTPSクライアント

Error Message

SSL certificate problem: self-signed certificate
#ssl#self-signed#certificate#curl

エラーの内容

HTTPSエンドポイントにアクセスすると、次のようなエラーが返ってきます:

curl: (60) SSL certificate problem: self-signed certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it.

サーバーが信頼された認証局(CA)から証明書を取得せず、自己署名のTLS証明書を使用しています。HTTPクライアントは信頼できる証明書チェーンを認識できないため、接続を拒否します。原因はこれだけです。

発生する原因

TLSクライアントにはLet's Encrypt、DigiCert、GlobalSignなどの信頼済みルートCAのリストが組み込まれています。自己署名証明書はこれらのいずれにも紐付かないため、ハンドシェイクが失敗します。よくある状況を以下に挙げます:

  • 正式な証明書を用意していない内部の開発・ステージングサーバー
  • Dockerコンテナ、ローカルKubernetesクラスター(kind、minikube)、またはプライベートAPI
  • HTTPSトラフィックを傍受して独自証明書で再署名する企業プロキシ
  • 有効期限切れの証明書を自己更新して使い続けているレガシーサーバー

修正方法1:自己署名証明書をトラストストアに追加する(正しい修正方法)

複数回アクセスするサーバーには、この方法が最適です。SSL検証を無効化せずに、特定の証明書だけを信頼できます。

手順1:サーバーから証明書を取得する

# サーバーの証明書をファイルに保存する
openssl s_client -connect your-server.example.com:443 -showcerts </dev/null 2>/dev/null \
  | openssl x509 -outform PEM > server-cert.pem

手順2:curlで証明書を使用する

curl --cacert server-cert.pem https://your-server.example.com/api/endpoint

手順3:システムのトラストストアに追加する

一度追加すると、そのマシン上のすべてのツールが自動的に信頼するようになります。

Ubuntu/Debianの場合:

sudo cp server-cert.pem /usr/local/share/ca-certificates/my-server.crt
sudo update-ca-certificates

RHEL/CentOS/Fedoraの場合:

sudo cp server-cert.pem /etc/pki/ca-trust/source/anchors/my-server.crt
sudo update-ca-trust

macOSの場合:

sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain server-cert.pem

Windows(管理者としてPowerShellを実行)の場合:

Import-Certificate -FilePath .\server-cert.pem -CertStoreLocation Cert:\LocalMachine\Root

修正方法2:SSL検証をスキップする(簡易修正 — 開発環境限定)

手軽な方法です。localhostや信頼できる内部ネットワークであれば問題ありません。ただし、本番環境に適用すると、いつか必ず問題が発生します。

curl

curl -k https://your-server.example.com/api/endpoint
# または長い形式
curl --insecure https://your-server.example.com/api/endpoint

Python(requestsライブラリ)

import requests

# 検証をスキップ — 開発環境限定。InsecureRequestWarningも抑制する:
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
response = requests.get('https://your-server.example.com/api', verify=False)

# より良い方法:証明書ファイルを直接指定する
response = requests.get('https://your-server.example.com/api', verify='/path/to/server-cert.pem')

Node.js(httpsモジュール)

const https = require('https');
const fs = require('fs');

// オプション1:検証を完全にスキップする(開発環境限定)
// HTTPSを呼び出す前に設定する
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

// オプション2:カスタムエージェントで証明書を指定する(node-fetchやaxiosでも使用可能)
const agent = new https.Agent({
  ca: fs.readFileSync('/path/to/server-cert.pem')
});

// axiosの場合:
const axios = require('axios');
axios.get('https://your-server.example.com/api', { httpsAgent: agent });

// node-fetchの場合:
const fetch = require('node-fetch');
fetch('https://your-server.example.com/api', { agent });

Git

# SSLをスキップして1回だけクローンする
git clone -c http.sslVerify=false https://your-server.example.com/repo.git

# 代わりに証明書を指定する(より安全)
git config --global http.sslCAInfo /path/to/server-cert.pem

# グローバルに無効化 — 動作はするが、すべての場所で脆弱になる
git config --global http.sslVerify false

wget

wget --no-check-certificate https://your-server.example.com/file.zip

修正方法3:自己署名証明書を正式な証明書に置き換える

サーバーを管理しているなら、正式な証明書を取得するのが最善です。公開HTTPアクセスのない内部サービスには、Let's EncryptのDNSチャレンジが最適です。ポート80を公開する必要はありません:

# DNSチャレンジ — 公開HTTPが不要
certbot certonly --manual --preferred-challenges dns -d your-internal-server.example.com

完全にエアギャップされた環境の場合は、step-caを使って内部CAを構築し、Ansible、グループポリシー、またはお好みの構成管理ツールを通じてルート証明書を全マシンに配布してください。ネットワーク内のすべてのサービスが正式な証明書を取得でき、自己署名の煩わしさから解放されます。

修正の確認

# SSLエラーなしでレスポンスが返る
curl -v https://your-server.example.com/

# 証明書の詳細を確認する
openssl s_client -connect your-server.example.com:443 </dev/null | openssl x509 -noout -text

# 証明書チェーンが正しく解決されることを確認する
curl --cacert server-cert.pem -v https://your-server.example.com/ 2>&1 | grep -E "SSL|certificate|issuer"

接続が成功すると、詳細出力に証明書の警告なしでSSL connection using TLSv1.3(またはTLSv1.2)と表示されます。

クイックリファレンス

  • 1回だけcurlでリクエストする場合-kフラグを使えばOK
  • 同じサーバーに繰り返しアクセスする場合:証明書をシステムのトラストストアに一度追加する
  • Pythonスクリプトverify=Falseではなくverify='/path/to/cert.pem'を使用する
  • 本番システム:自己署名証明書は必ず置き換える — 例外なし
  • 企業プロキシでブロックされる場合:IT部門にプロキシCAの証明書を入手し、トラストストアに追加する

Related Error Notes