---
title: "خطای ⁦Unable to Get Local Issuer Certificate⁩ و راه رفع آن"
description: "خطای unable to get local issuer certificate یعنی ابزار شما CA امضاکننده زنجیره گواهی سرور را پیدا نمی‌کند. سه علت و راه رفع در Python، npm، Git و curl."
url: https://proxynet.io/fa/blog/unable-to-get-local-issuer-certificate
date: 2026-10-06
author: "Acar Diveroli"
category: "آموزش‌ها, وب اسکرپینگ"
lang: fa
---

# خطای ⁦Unable to Get Local Issuer Certificate⁩ و راه رفع آن

روی لپ‌تاپ محل کارتان `npm install` را اجرا می‌کنید و فرمان با `npm error code UNABLE_TO_GET_ISSUER_CERT_LOCALLY` متوقف می‌شود. رجیستری npm روی همان دستگاه در کروم بی‌مشکل باز می‌شود و همکاری که از خانه کار می‌کند همان بسته‌ها را بدون دردسر نصب می‌کند. یک اسکریپت Python با `CERTIFICATE_VERIFY_FAILED` شکست می‌خورد و `git clone` از یک مشکل گواهی SSL خبر می‌دهد. رجیستری هیچ ایرادی ندارد: ابزارهای شما و مرورگرتان به فهرست‌های متفاوتی از مراجع صدور گواهی اعتماد دارند.

این راهنما توضیح می‌دهد کلاینت دقیقاً چه چیزی را بررسی می‌کند، سه علت را با خطاهایی که روی سرورهای آزمایشی محلی بازتولید کرده‌ایم از هم جدا می‌کند و راه رفع را برای Python، npm، Git و curl و سپس برای سمت سرور ارائه می‌دهد.

> **نکته: پاسخ کوتاه**
>
> کلاینت شما نتوانست زنجیره گواهی سرور را به ریشه‌ای در فهرست ریشه‌های مورد اعتماد خودش، یعنی مخزن اعتماد محلی (trust store)، برساند. سه علت وجود دارد: سرور گواهی میانی خود را نمی‌فرستد؛ یک پروکسی یا آنتی‌ویروس که TLS را بازرسی می‌کند ترافیک را با ریشه‌ای دوباره امضا می‌کند که ابزار شما ندارد؛ یا ابزار شما به‌جای مخزن سیستم، فایل CA خودش (CA bundle) را می‌خواند. ریشه درست را همان جایی بگذارید که ابزار به آن نگاه می‌کند (`truststore` یا `REQUESTS_CA_BUNDLE`، `NODE_EXTRA_CA_CERTS`، Schannel یا `http.sslCAInfo`، `--cacert`) یا زنجیره سرور را اصلاح کنید. `verify=False` و `-k` فقط خطا را پنهان می‌کنند.

## «unable to get local issuer certificate» یعنی چه؟

یک گواهی TLS نام صاحب خود (subject) و نام مرجع صدور گواهی (CA) را که آن را امضا کرده (issuer) در خود دارد. سرور گواهی خودش را که به آن گواهی برگ (leaf) می‌گویند، همراه یک یا چند گواهی میانی می‌فرستد که آن را به یک گواهی ریشه وصل می‌کنند. گواهی‌های ریشه هنگام اتصال فرستاده نمی‌شوند: هر کلاینت مجموعه ریشه‌های مورد اعتماد خودش، یعنی مخزن اعتماد، را نگه می‌دارد و واژه «local» (محلی) در پیام به همین مجموعه اشاره دارد.

این متن خطای شماره 20 در تأیید OpenSSL است: `X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY`. کلاینت به گواهی‌ای رسیده که صادرکننده‌اش را نه میان گواهی‌هایی که سرور فرستاده پیدا کرده و نه در مخزن خودش. دست‌دادن TLS پیش از ارسال درخواست شما متوقف می‌شود.

## تأیید زنجیره گواهی چگونه کار می‌کند؟

1. **سرور زنجیره‌اش را می‌فرستد.** نخست گواهی برگ می‌آید، هر گواهی بعدی گواهی پیش از خود را امضا می‌کند و ریشه ممکن است فرستاده نشود، چون کلاینت‌ها آن را از قبل دارند ([بخش 4.4.2 از ⁦RFC 8446⁩](https://www.rfc-editor.org/rfc/rfc8446.html#section-4.4.2)).
2. **کلاینت گواهی برگ را بررسی می‌کند:** نام باید با میزبان در URL یکی باشد و تاریخ‌ها باید معتبر باشند.
3. **کلاینت صادرکننده هر گواهی را پیدا می‌کند،** آن را میان گواهی‌های فرستاده‌شده می‌جوید، امضا را بررسی می‌کند و همین کار را یک سطح بالاتر تکرار می‌کند.
4. **بالای زنجیره باید به مخزن اعتماد برسد،** یعنی ریشه‌ای که کلاینت از قبل به آن اعتماد دارد باید آن را امضا کرده باشد.
5. **یک حلقه گم‌شده دست‌دادن را متوقف می‌کند** و متن خطا به جایی بستگی دارد که زنجیره در آن قطع شده است.

مخزن اعتماد به ابزار بستگی دارد، نه به دستگاه. Requests از certifi استفاده می‌کند، بسته‌ای در Python که فهرست ریشه‌های موزیلا را در خود دارد؛ Node.js در هر نسخه، تصویری از مخزن موزیلا را درون خود کامپایل می‌کند؛ Git for Windows فایل `ca-bundle.crt` خودش یا مخزن ویندوز را می‌خواند. به همین دلیل روی یک لپ‌تاپ، یک برنامه ممکن است شکست بخورد در حالی که برنامه دیگری موفق می‌شود.

## سه پیام خطا، یک خانواده

با OpenSSL یک ریشه، یک میانی و یک برگ ساختیم، سه سرور HTTPS محلی راه انداختیم که بخش‌های متفاوتی از زنجیره را می‌فرستند و آن‌ها را روی ویندوز 11 از ⁦Python 3.13.9⁩ (⁦Requests 2.34.2⁩)، ⁦Node.js 24.11.1⁩ (⁦npm 11.6.2⁩)، ⁦curl 8.21.0⁩ و ⁦Git 2.55⁩ با OpenSSL فراخواندیم. هیچ‌کدام از ابزارها ریشه ما را نمی‌شناخت.

| آنچه سرور فرستاد | Python (`ssl`، Requests) | Node.js و npm | curl و Git (OpenSSL) |
|---|---|---|---|
| برگ + میانی | `unable to get local issuer certificate` | `UNABLE_TO_GET_ISSUER_CERT_LOCALLY` | `unable to get local issuer certificate (20)` |
| فقط برگ | `unable to get local issuer certificate` | `UNABLE_TO_VERIFY_LEAF_SIGNATURE` | `unable to get local issuer certificate (20)` |
| برگ + میانی + ریشه | `self-signed certificate in certificate chain` | `SELF_SIGNED_CERT_IN_CHAIN` | `self-signed certificate in certificate chain (19)` |

Python و curl برای گواهی میانی گم‌شده و ریشه ناشناخته از یک عبارت استفاده می‌کنند، پس فقط خود زنجیره نشان می‌دهد کدام طرف را باید اصلاح کرد. سطر سوم همان مشکل است، با این تفاوت که ریشه هم فرستاده شده: سرور، یا پروکسی‌ای در میانه راه، ریشه‌ای فرستاده که ابزار شما به آن اعتماد ندارد.

## سه علت پشت این خطا

### 1. سرور گواهی میانی خود را نمی‌فرستد

مدیر سرور فقط گواهی برگ را نصب کرده است، پس هر کلاینتی که گواهی میانی را نداشته باشد، روی هر شبکه‌ای شکست می‌خورد. مرورگرها اغلب این مشکل را پنهان می‌کنند: به توضیح موزیلا، فایرفاکس گواهی‌های میانی شناخته‌شده را از پیش همراه خود دارد و مرورگرهای دیگر گواهی گم‌شده را در پس‌زمینه دانلود می‌کنند. Python، Node.js، curl و Git هیچ‌کدام از این دو کار را نمی‌کنند، پس «در کروم کار می‌کند» چیزی را ثابت نمی‌کند.

### 2. پروکسی یا آنتی‌ویروسی که TLS را بازرسی می‌کند ترافیک را دوباره امضا می‌کند

گیت‌وی‌های وب سازمانی، آنتی‌ویروس‌هایی که اسکن HTTPS دارند و ابزارهای اشکال‌زدایی مانند mitmproxy، Charles و Fiddler اتصال رمزگذاری‌شده را باز می‌کنند و برای سایت گواهی تازه‌ای ارائه می‌دهند که با ریشه خودشان امضا شده است. تیم IT این ریشه را در مخزن سیستم لپ‌تاپ‌های مدیریت‌شده نصب می‌کند، پس مرورگرها آن را می‌پذیرند؛ اما ابزارهایی که فهرست خودشان را دارند نمی‌پذیرند. نشانه‌ها: خطا روی شبکه دفتر یا VPN ظاهر می‌شود، نه در خانه، و تقریباً همه سایت‌ها را درگیر می‌کند. اگر خودتان چنین ابزاری را اجرا می‌کنید، مرحله گواهی ریشه آن در نوشته [پروکسی MITM چیست؟](/fa/blog/mitm-proxy) آمده است.

### 3. ابزار شما به فهرستی جدا از فهرست سیستم اعتماد دارد

فایل‌های CA در Requests، Node.js و Git هرگز ریشه‌ای را که شرکت شما در ویندوز یا macOS نصب کرده، یا CA خصوصی‌ای را که سرویس‌های داخلی را امضا می‌کند، نمی‌بینند. Python که با نصب‌کننده macOS از python.org نصب شده باشد، به همین دلیل یک مرحله گواهی جداگانه لازم دارد و سیستم‌ها و فایل‌های CA قدیمی ممکن است ریشه‌های عمومی تازه‌تر را نداشته باشند.

## چگونه بفهمید با کدام علت روبه‌رو هستید؟

به زنجیره‌ای نگاه کنید که سرور واقعاً می‌فرستد. Git for Windows همراه خود `openssl` دارد، پس این فرمان در Git Bash هم اجرا می‌شود:

```bash
openssl s_client -connect localhost:47444 -servername localhost -showcerts </dev/null
```

سرور ما روی پورت 47444 فقط گواهی برگ را می‌فرستد. سطرهای مهم:

```text
Certificate chain
 0 s:CN=localhost
   i:O=Example Corp, CN=Example Corp Issuing CA
Verify return code: 21 (unable to verify the first certificate)
```

`s:` موضوع (subject) و `i:` صادرکننده (issuer) است؛ زنجیره کامل یک مدخل `1 s:` هم دارد. برای حالت بازرسی، یک پروکسی محلی اجرا کردیم که مانند گیت‌وی سازمانی ترافیک را با CA به نام Example Corp دوباره امضا می‌کند و `example.com` را از طریق آن درخواست کردیم (`-proxy 127.0.0.1:47461`):

```text
Certificate chain
 0 s:CN=example.com
   i:O=Example Corp, CN=Example Corp Issuing CA
 1 s:O=Example Corp, CN=Example Corp Issuing CA
   i:O=Example Corp, CN=Example Corp Root CA
Verify return code: 20 (unable to get local issuer certificate)
```

از طریق یک تونل ساده، همان فرمان زنجیره واقعی سایت را نشان داد که `Cloudflare TLS Issuing ECC CA 3` آن را صادر کرده بود، همراه با `Verify return code: 0 (ok)`. خروجی خودتان را این‌طور بخوانید:

- **فقط مدخل 0، صادرکننده عمومی:** سرور گواهی میانی خود را نمی‌فرستد (علت 1).
- **صادرکننده شرکت شما، یک محصول امنیتی یا یک ابزار اشکال‌زدایی است:** چیزی ترافیک را دوباره امضا می‌کند (علت 2).
- **زنجیره عمومی کامل و `0 (ok)`، اما ابزار شما شکست می‌خورد:** ابزار مخزن اعتماد دیگری را می‌خواند (علت 3).

## چگونه این خطا را در Python رفع کنیم؟

Requests این خطا را درون سطری طولانی‌تر می‌پیچد؛ نوشته [خطای Max Retries Exceeded With URL](/fa/blog/max-retries-exceeded-with-url) توضیح می‌دهد بخش `Caused by` آن را چگونه بخوانید. آزمون ما این خروجی را داد:

```text
requests.exceptions.SSLError: HTTPSConnectionPool(host='localhost', port=47443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1032)')))
```

اگر تیم IT ریشه شرکت را در سیستم‌عامل نصب کرده است، بگذارید Python از همان مخزن استفاده کند. بسته `truststore` (⁦Python 3.10⁩ یا بالاتر) کاری می‌کند که Requests و ماژول `ssl` از طریق مخزن سیستم تأیید کنند؛ مستندات آن استفاده از `inject_into_ssl()` را به برنامه‌ها و اسکریپت‌ها محدود می‌کند، نه کتابخانه‌ها:

```python
import truststore
truststore.inject_into_ssl()  # call once, at the start of your script

import requests

print(requests.get("https://example.com/", timeout=10).status_code)
```

در غیر این صورت، فایل CA تازه‌ای با ریشه‌های certifi به‌اضافه ریشه شرکت بسازید و `REQUESTS_CA_BUNDLE` را به آن اشاره دهید:

```bash
cat "$(python -m certifi)" corp-root.pem > ca-bundle-plus-corp.pem
export REQUESTS_CA_BUNDLE="$PWD/ca-bundle-plus-corp.pem"
```

پس از آن هم `example.com` و هم سرور آزمایشی ما `200` برگرداندند. هرگز ریشه شرکت را به‌تنهایی به کار نبرید: این متغیر جای certifi را می‌گیرد و در آزمون ما `example.com` در آن حالت با همان خطا شکست خورد. پس از هر به‌روزرسانی certifi فایل را دوباره بسازید.

برخلاف Requests، pip از نسخه 24.2 از گواهی‌های سیستم هم استفاده می‌کند ([مستندات pip](https://pip.pypa.io/en/stable/topics/https-certificates/))، پس `pip install` ممکن است جایی کار کند که Requests شکست می‌خورد. برای یک فایل CA مشخص، `--cert` را بدهید یا `PIP_CERT` را تنظیم کنید. در macOS با نصب‌کننده python.org، فایل `Install Certificates.command` را یک بار اجرا کنید.

اگر سایتی که از آن داده جمع می‌کنید گواهی میانی‌اش را نمی‌فرستد، آن را از CA صادرکننده دانلود کنید و به فایل ترکیبی بیفزایید (همین کار سرور فقط‌برگ ما را از آزمون گذراند) و به صاحب سایت خبر بدهید.

## چگونه این خطا را در Node.js و npm رفع کنیم؟

خروجی npm همان کد Node.js را در خود دارد:

```text
npm error code UNABLE_TO_GET_ISSUER_CERT_LOCALLY
npm error errno UNABLE_TO_GET_ISSUER_CERT_LOCALLY
npm error request to https://localhost:47443/demo-pkg failed, reason: unable to get local issuer certificate
```

Node.js ریشه‌های فایلی را که `NODE_EXTRA_CA_CERTS` نام می‌برد به فهرست داخلی خود اضافه می‌کند ([مستندات Node.js](https://nodejs.org/api/cli.html#node_extra_ca_certsfile)). npm روی Node.js اجرا می‌شود، پس یک متغیر هر دو را درست می‌کند:

```bash
export NODE_EXTRA_CA_CERTS="$PWD/corp-root.pem"
npm view demo-pkg version --registry https://localhost:47443/
```

فرمان دوم `1.0.0` را چاپ کرد (در PowerShell: `$env:NODE_EXTRA_CA_CERTS = "C:\certs\corp-root.pem"`). Node.js این متغیر را فقط هنگام راه‌اندازی می‌خواند، نه از درون اسکریپتی که در حال اجراست.

اما تنظیم `cafile` خود npm فهرست مورد اعتماد را جایگزین می‌کند. وقتی فقط ریشه شرکت در آن بود، درخواست ما به رجیستری عمومی شکست خورد:

```text
npm error request to https://registry.npmjs.org/left-pad failed, reason: unable to get local issuer certificate
```

اگر ریشه از قبل در مخزن سیستم است، Node.js می‌تواند همان مخزن را بخواند: `--use-system-ca` در ⁦Node.js 23.8.0⁩ و `NODE_USE_SYSTEM_CA=1` در نسخه‌های 24.6.0 و 22.19.0 اضافه شد و هر دو در آزمون ما با npm کار کردند (`NODE_OPTIONS=--use-system-ca`). دستیارهای برنامه‌نویسی مبتنی بر هوش مصنوعی که بر پایه Node.js ساخته شده‌اند همین متغیرها را می‌خوانند؛ مستندات Claude Code متغیر `NODE_EXTRA_CA_CERTS` را برای CAهای سازمانی فهرست کرده است.

## چگونه این خطا را در Git رفع کنیم؟

Git با بک‌اند OpenSSL همان عبارت‌بندی curl را نشان می‌دهد:

```text
fatal: unable to access 'https://localhost:47443/repo.git/': SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
```

در ویندوز، بگذارید Git از مخزن ویندوز استفاده کند. نصب‌کننده Git for Windows دو گزینه ⁦"Use the OpenSSL library"⁩ (استفاده از کتابخانه OpenSSL) و ⁦"Use the native Windows Secure Channel library"⁩ (استفاده از کتابخانه بومی Secure Channel ویندوز) را پیشنهاد می‌کند؛ بعداً هم می‌توانید آن را تغییر دهید:

```bash
git config --global http.sslBackend schannel
```

اگر ریشه آنجا هم نباشد، Schannel خطای `SEC_E_UNTRUSTED_ROOT (0x80090325)` را گزارش می‌کند. متن این پیام به زبان سیستم است و در ویندوز انگلیسی ⁦"The certificate chain was issued by an authority that is not trusted"⁩ نوشته می‌شود، یعنی زنجیره گواهی را مرجعی صادر کرده که مورد اعتماد نیست. Schannel تنظیم `http.sslCAInfo` را نادیده می‌گیرد، مگر آنکه `http.schannelUseSSLCAInfo` تنظیم شده باشد.

روی macOS، لینوکس یا بک‌اند OpenSSL، Git را فقط برای یک سرور به یک فایل ارجاع دهید:

```bash
git config --global http.https://git.example.com/.sslCAInfo /path/to/corp-root.pem
```

در آزمون ما، میزبان پیکربندی‌شده از TLS گذشت، میزبان دیگر همچنان شکست خورد و `github.com` همچنان کار می‌کرد. اگر گیت‌وی همه سایت‌ها را بازرسی می‌کند، از Schannel یا یک فایل ترکیبی (فایل CA خود Git به‌اضافه ریشه شرکت) استفاده کنید.

## چگونه این خطا را در curl رفع کنیم؟

شماره این خطا در curl عدد 60 است. ⁦curl 8.21.0⁩ ما آن را این‌طور بیان می‌کند؛ بیلدهای دیگر `SSL certificate problem: unable to get local issuer certificate` را چاپ می‌کنند:

```text
curl: (60) SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
More details here: https://curl.se/docs/sslcerts.html
```

- **`--cacert corp-root.pem`** تأیید را با همان فایل انجام می‌دهد و جای فایل CA پیش‌فرض را می‌گیرد، پس برای سایت‌های عمومی هم از یک فایل ترکیبی استفاده کنید.
- **`--ca-native`** (⁦curl 8.2.0⁩ به بعد) مخزن سیستم را به بیلدهای OpenSSL در ویندوز اضافه می‌کند، و در macOS هم وقتی curl با SecTrust اپل ساخته شده باشد.
- **`curl.exe` داخلی ویندوز** از Schannel و مخزن ویندوز استفاده می‌کند. با CA خصوصی‌ای که هیچ داده ابطالی منتشر نمی‌کند، در `schannel: the revocation status is unknown` متوقف می‌شود؛ `--ssl-revoke-best-effort` این وضعیت را می‌پذیرد و همچنان زنجیره را بررسی می‌کند.
- **`--proxy-cacert`** یک پروکسی HTTPS را تأیید می‌کند، یعنی پروکسی‌ای که با آدرس `https://` به آن وصل می‌شوید. پروکسی ساده `http://` گواهی خودش را ندارد؛ نوشته [استفاده از cURL با پروکسی](/fa/blog/curl-proxy) هر دو حالت را پوشش می‌دهد.

صفحه پروژه curl درباره [تأیید گواهی SSL](https://curl.se/docs/sslcerts.html) اکیداً توصیه می‌کند در محیط عملیاتی هرگز تأیید را کنار نگذارید.

## چرا ⁦verify=False⁩، ⁦-k⁩ و ⁦NODE_TLS_REJECT_UNAUTHORIZED=0⁩ راه‌حل نیستند؟

این‌ها به‌جای ترمیم زنجیره، بررسی آن را متوقف می‌کنند، پس کلاینت هر گواهی‌ای را برای هر نامی می‌پذیرد، حتی گواهی کسی که روی همان شبکه است و می‌خواهد ترافیک شما را بخواند؛ مستندات Node.js با صراحت `NODE_TLS_REJECT_UNAUTHORIZED=0` را ناامن می‌نامد. در آزمون Git ما، `http.sslVerify=false` بدون هیچ هشداری به سرور رسید، پس پیکربندی خراب همان‌طور باقی می‌ماند. چنین کلیدهایی گسترش هم پیدا می‌کنند: متغیری در پروفایل شل به همه برنامه‌های Node.js می‌رسد و `verify=False` یک آزمون سر از محیط عملیاتی درمی‌آورد.

## چگونه از سرور خودتان زنجیره کامل بفرستید؟

گواهی برگ و پس از آن همه گواهی‌های میانی را پیکربندی کنید و ریشه را کنار بگذارید. در nginx، فایل `ssl_certificate` نخست گواهی سرور و پس از آن گواهی‌های میانی را در خود دارد ([مستندات nginx](https://nginx.org/en/docs/http/configuring_https_servers.html#chains))؛ اگر ترتیب اشتباه باشد، nginx با `key values mismatch` راه‌اندازی نمی‌شود. Certbot برای همین کار `fullchain.pem` را می‌نویسد، در حالی که `cert.pem` فقط گواهی برگ را دارد؛ ⁦Apache 2.4.8⁩ و بالاتر `fullchain.pem` را در `SSLCertificateFile` می‌پذیرد. از بیرون با `openssl s_client -connect yourdomain:443 -servername yourdomain -showcerts` بررسی کنید: باید مدخل‌های `0` و `1` و `Verify return code: 0 (ok)` را ببینید.

دو تغییر در 2026 خودکار کردن این بررسی را ارزشمند می‌کند. از 15 مارس 2026، الزامات پایه (Baseline Requirements) ⁦CA/Browser Forum⁩ اعتبار گواهی‌های عمومی را به 200 روز محدود کرده است (100 روز از مارس 2027 و 47 روز از مارس 2029)، پس تمدیدها بیشتر می‌شوند و هر تمدید فرصتی است برای نصب فایل نادرست. در 27 مه 2026، Let's Encrypt پروفایل پیش‌فرض خود را به گواهی‌های میانی Generation Y منتقل کرد که از طریق امضای متقابل (cross-sign) به ریشه‌های آشنای ISRG می‌رسند؛ Certify The Web، یک کلاینت گواهی برای ویندوز، مستند کرده است که سرورهای ویندوزی زنجیره کوتاه‌تر به ریشه‌های جدید را می‌فرستند، زنجیره‌ای که کلاینت‌های قدیمی‌تر نمی‌توانند تأییدش کنند.

## آیا پروکسی باعث این خطا می‌شود؟

فقط پروکسی‌ای که ترافیک را رمزگشایی می‌کند. برای درخواست `https://` از طریق پروکسی HTTP، کلاینت `CONNECT host:443` را می‌فرستد و پروکسی بایت‌های رمزگذاری‌شده را جابه‌جا می‌کند، پس شما گواهی خود سایت را تأیید می‌کنید، همان‌طور که تونل ساده ما نشان داد. گیت‌وی‌های Proxynet هم تونل ساده‌اند: اتصال [پروکسی HTTPS](https://proxynet.io/fa/https-proxy) به هیچ گواهی ریشه‌ای روی دستگاه شما نیاز ندارد.

وقتی از طریق استخر [پروکسی مسکونی](https://proxynet.io/fa/residential-proxy) داده جمع‌آوری می‌کنید، آدرس خروجی تغییر می‌کند اما گواهی سایت نه، پس خطای زنجیره روی یک هدف در همه آدرس‌های خروجی همراه شما می‌ماند؛ چرخاندن IP آن را برطرف نمی‌کند.

## کجا با این خطا روبه‌رو می‌شوید

- **نصب بسته روی لپ‌تاپ شرکت:** npm، pip و yarn پشت گیت‌وی‌ای که TLS را بازرسی می‌کند شکست می‌خورند، در حالی که مرورگر کار می‌کند.
- **رانرهای CI و بیلدهای Docker:** کانتینر مخزن اعتماد خودش را دارد، پس ریشه شرکت باید داخل ایمیج قرار بگیرد.
- **دستیارهای برنامه‌نویسی مبتنی بر هوش مصنوعی:** ابزارهای خط فرمانی که بر پایه Node.js ساخته شده‌اند، API خود را از طریق همان گیت‌وی فرا می‌خوانند.
- **کلاینت‌های API:** در Postman، **Settings** (تنظیمات) و سپس **Certificates** (گواهی‌ها) را باز کنید، **CA certificates** (گواهی‌های CA) را روشن کنید و فایل PEM را انتخاب کنید.
- **اسکرپرها:** سایتی که گواهی میانی‌اش گم شده، در همه اسکریپت‌ها شکست می‌خورد در حالی که در مرورگر باز می‌شود.
- **سرویس‌های داخلی:** داشبوردها و سرورهای Git که CA شرکت آن‌ها را امضا کرده است.

## اشتباهات رایج

- **ارجاع `REQUESTS_CA_BUNDLE`، `cafile` در npm یا `--cacert` فقط به ریشه شرکت.** هر سه فهرست پیش‌فرض را جایگزین می‌کنند.
- **افزودن گواهی نادرست.** فایل باید ریشه‌ای را داشته باشد که تیم IT منتشر می‌کند، نه گواهی برگ یک سایت.
- **ذخیره گواهی در قالب دودویی DER.** این تنظیمات PEM می‌خواهند، یعنی قالب متنی که با `-----BEGIN CERTIFICATE-----` شروع می‌شود.
- **تنظیم `NODE_EXTRA_CA_CERTS` درون اسکریپت.** Node.js آن را فقط هنگام راه‌اندازی می‌خواند.
- **نصب `cert.pem` به‌جای `fullchain.pem`.** مرورگرها ممکن است همچنان کار کنند، پس کسی متوجه نمی‌شود.

## راهنمای انتخاب

| آنچه می‌بینید | چه باید کرد |
|---|---|
| فقط مدخل `0`، صادرکننده عمومی | صاحب سایت زنجیره کامل را بفرستد؛ تا آن زمان گواهی میانی را به فایل CA خود بیفزایید |
| صادرکننده شرکت شما، آنتی‌ویروس یا ابزار اشکال‌زدایی است | آن ریشه را از تیم IT بگیرید و برای هر ابزار جداگانه اضافه کنید |
| زنجیره عمومی و `0 (ok)`، اما یک ابزار شکست می‌خورد | بگذارید ابزار مخزن سیستم را بخواند: truststore، `--use-system-ca`، Schannel |
| npm شکست می‌خورد | `NODE_EXTRA_CA_CERTS`؛ `cafile` فقط با فایل CA کامل |
| Git برای یک سرور داخلی شکست می‌خورد | `http.<url>.sslCAInfo` برای همان میزبان |
| curl شکست می‌خورد | `--cacert` با فایل ترکیبی، یا `--ca-native` |

## پرسش‌های متداول

### چرا سایت در مرورگر من باز می‌شود اما در Python، curl یا Node.js شکست می‌خورد؟

مرورگر و ابزار مخزن‌های اعتماد متفاوتی را می‌خوانند و مرورگرها زنجیره‌های ناقص را خودشان ترمیم می‌کنند. اسکریپت فایل CA خودش را می‌خواند و هیچ‌کدام از این دو کار را نمی‌کند؛ زنجیره را با `openssl s_client` مقایسه کنید تا ببینید کدام حالت صدق می‌کند.

### آیا استفاده از ⁦verify=False⁩، ⁦-k⁩ یا ⁦NODE_TLS_REJECT_UNAUTHORIZED=0⁩ امن است؟

نه به‌عنوان راه‌حل. این‌ها همه بررسی‌های گواهی را خاموش می‌کنند، پس هر کسی میان شما و سرور می‌تواند ترافیک را بخواند یا تغییر دهد. حداکثر برای یک فرمان روی سرور آزمایشی خودتان از آن‌ها استفاده کنید.

### تفاوت «unable to get local issuer certificate» با «self-signed certificate in certificate chain» چیست؟

هر دو یعنی زنجیره به ریشه‌ای ختم می‌شود که ابزار شما به آن اعتماد ندارد. در اولی، ریشه فرستاده نشده و به‌صورت محلی هم پیدا نشده است؛ در دومی، سرور یا یک پروکسی خود ریشه را فرستاده است. راه رفع یکی است.

### گواهی ریشه شرکتم را از کجا بگیرم؟

از تیم IT یا امنیت؛ روی لپ‌تاپ مدیریت‌شده این گواهی از قبل در مخزن سیستم هست، پس truststore، `--use-system-ca` و Schannel بدون فایل کار می‌کنند. هرگز ریشه‌ای را از منبع غیررسمی نگیرید: یک ریشه مورد اعتماد می‌تواند برای هر دامنه‌ای گواهی امضا کند.

### چرا pip روی همان دستگاه کار می‌کند اما Requests شکست می‌خورد؟

pip از نسخه 24.2 علاوه بر certifi گواهی‌های سیستم را هم بررسی می‌کند، در حالی که Requests فقط certifi را می‌خواند. بسته truststore همین رفتار را به اسکریپت شما می‌دهد.

### آیا پروکسی می‌تواند باعث خطای «unable to get local issuer certificate» شود؟

فقط پروکسی‌ای که ترافیک را رمزگشایی می‌کند: گیت‌وی سازمانی، آنتی‌ویروس با اسکن HTTPS یا پروکسی اشکال‌زدایی. پروکسی تونلی که از `CONNECT` استفاده می‌کند، گواهی خود سایت را بدون تغییر عبور می‌دهد.

## خلاصه

این خطا یعنی کلاینت شما نتوانست گواهی سرور را به ریشه‌ای که به آن اعتماد دارد وصل کند. `openssl s_client` علت را نشان می‌دهد: گواهی برگ تنها به سرور اشاره دارد، صادرکننده سازمانی به بازرسی TLS و زنجیره عمومی سالم به فایل CA خود ابزار. ریشه درست را همان جایی بگذارید که ابزار به آن نگاه می‌کند و تأیید را روشن نگه دارید. برای پروکسی‌هایی که ترافیک را بدون دست زدن به گواهی‌ها تونل می‌کنند، [خدمات پروکسی ما](/fa/proxy) را ببینید.
