[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"content-setup-npm-proxy":3,"$f12ui9a66dtyz":25},{"id":4,"type":5,"slug":6,"title":7,"date":8,"category":9,"tags":10,"body_markdown":17,"permalink":18,"excerpt_src":18,"media_type":18,"media_title":18,"media_author":18,"media_url":18,"rating":18,"layout":18,"pv":19,"admin_only":19,"created_at":20,"updated_at":20,"deleted_at":18,"status":21,"html":22,"excerpt":23,"cover":24},192,"article","setup-npm-proxy","NPM代理搭建指南","2024-11-16 16:00","web",[11,12,13,14,15,16],"NPM","代理","反向代理","SSL","证书","VPN","\n最近在家里开发项目的时候，时常碰到npm安装超时。想了一下手上有好多服务器，应该能解决这个问题，于是我搭建了一个代理服务器。\n\n## 技术方案概述\n\nnpm registry有两个主要地址：\n\n- https:\u002F\u002Fregistry.npmjs.com\n- https:\u002F\u002Fregistry.npmjs.org\n\n需要让npm客户端访问这两个域名的时候走自己的服务器，并突破封锁。\n\n\u003C!-- more -->\n\n本方案概要：\n\n- 使用Nginx搭建反向代理服务器\n- 自签名SSL证书并设置信任\n- 使用TailScale VPN实现网络互通\n- hosts文件配置域名解析\n\n其中TailScale是一个基于WireGuard的现代VPN解决方案，它是本方案中不可或缺的组件，因为它能够帮助我们：\n\n- 通过零配置组网快速建立安全通道\n- 利用 WireGuard 的高性能加密通信确保数据安全\n- 实现 NAT 穿透，突破网络封锁\n- 支持多平台部署\n\n> 为什么不直接使用梯子：一方面是因为梯子流量有限，安装npm包会消耗大量流量；另一方面是我主要使用浏览器插件来分流，因此梯子没有配置按域名分流，无法针对npm的请求进行分流。\n\n> 为什么不使用npm镜像：因为通过npm镜像安装的话，lock文件也会使用镜像地址，这样在CI\u002FCD环境中可能会出现新的问题。\n\n## SSL证书配置与信任\n\n为了确保npm客户端信任我们自己搭的反向代理，我们需要配置并信任自签名证书。整个过程分为三步：生成根证书（CA）、生成服务器证书、添加证书信任。\n\n### 生成根证书（CA）\n\n这个脚本完成以下工作：\n- 生成 2048 位的 CA 私钥\n- 创建证书签名请求（CSR）\n- 设置基本约束和密钥用途\n- 生成有效期为10年的CA证书\n\n```sh\n#!\u002Fbin\u002Fbash\nset -o errexit\n\n# Generate CA private key\nopenssl genrsa -out ca.key 2048\n\n# Generate CA certificate signing request\nopenssl req -new -key ca.key -out ca.csr -sha256 \\\n    -subj \"\u002FC=CN\u002FST=GuangDong\u002FL=Shenzhen\u002FO=Tinkink\u002FOU=Tinkink\u002FCN=tinkink.net\"\n\n# Create ca.ext file\necho \"basicConstraints=CA:TRUE\nkeyUsage=keyCertSign,cRLSign\" > ca.ext\n\n# Generate CA certificate\nopenssl x509 -req -in ca.csr -signkey ca.key -out ca.crt \\\n    -extfile ca.ext -sha256 -days 3650\n```\n\n### 生成服务器证书\n\n这个脚本完成以下工作：\n\n- 生成服务器私钥\n- 创建服务器证书签名请求\n- 配置证书扩展信息，包括多域名支持\n- 使用之前创建的 CA 证书签发服务器证书\n\n```sh\n#!\u002Fbin\u002Fbash\n\n# Generate private key for npm\nopenssl genrsa -out npm.key 2048\n\n# Generate certificate signing request\nopenssl req -new -key npm.key -out npm.csr -sha256 \\\n    -subj \"\u002FC=CN\u002FST=GuangDong\u002FL=Shenzhen\u002FO=Tinkink\u002FOU=Tinkink\u002FCN=registry.npmjs.org\"\n\n# Create npm.ext file\necho \"authorityKeyIdentifier=keyid,issuer\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment\nsubjectAltName=@alt_names\n\n[alt_names]\nDNS.1=registry.npmjs.org\nDNS.2=registry.npmjs.com\" > npm.ext\n\n# Generate certificate\nopenssl x509 -req -in npm.csr -CA ca.crt -CAkey ca.key \\\n    -CAcreateserial -out npm.crt -extfile npm.ext -sha256 -days 720\n```\n\n### 证书信任配置\n\n生成证书后，需要将 CA 证书（ca.crt）添加到系统的信任存储中：\n\n**Windows**:\n\n1. 双击证书文件\n2. 选择\"安装证书\" -> \"本地计算机\"（需要管理员权限）\n3. 选择\"受信任的根证书颁发机构\"\n4. 也可以使用管理员权限运行 PowerShell 命令：\n\n```powershell\nImport-Certificate -FilePath \"ca.crt\" -CertStoreLocation Cert:\\LocalMachine\\Root\n```\n\n**Mac**:\n\n1. 双击证书文件，添加到钥匙串访问\n2. 在钥匙串访问中找到证书，双击展开\n3. 展开\"信任\"选项，将\"使用此证书时\"设置为\"始终信任\"\n\n**Linux**:\n\n```bash\nsudo cp ca.crt \u002Fusr\u002Flocal\u002Fshare\u002Fca-certificates\u002F\nsudo update-ca-certificates\n```\n\n## Nginx 反向代理配置\n\n在服务器上先配置好TailScale VPN，确保本地和服务器在同一个网络中。然后使用以下 Nginx 配置文件：\n\n```nginx\nserver {\n    listen 80;\n    server_name registry.npmjs.com registry.npmjs.org;\n\n    # Redirect all HTTP requests to HTTPS\n    return 301 https:\u002F\u002F$host$request_uri;\n}\n\nserver {\n    listen 443 ssl;\n    server_name registry.npmjs.com registry.npmjs.org;\n\n    ssl_certificate \u002Fetc\u002Fnginx\u002Fssl\u002Fnpm.crt;\n    ssl_certificate_key \u002Fetc\u002Fnginx\u002Fssl\u002Fnpm.key;\n\n    ssl_protocols TLSv1.2 TLSv1.3;\n\n    # Define the DNS resolver\n    resolver 8.8.8.8 8.8.4.4 valid=30s; # You can use Google's public DNS or any resolver you prefer\n    resolver_timeout 5s;\n\n    # Proxy requests to npm registry\n    location \u002F {\n        proxy_pass https:\u002F\u002F$host;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n\n        # Proxy settings to handle large requests and timeouts\n        proxy_read_timeout 90;\n        proxy_connect_timeout 90;\n        proxy_redirect off;\n\n        # Optionally, if you need to handle large response or request sizes\n        client_max_body_size 50M;\n    }\n}\n```\n\n这里重点说明两个关键配置：\n\n1. `resolver`配置用来指定当nginx访问npm registry时的DNS解析服务器，这里使用了Google的公共DNS服务器，如果不设置的话会报错\n2. `proxy_pass https:\u002F\u002F$host`：使用 `$host` 变量而不是硬编码域名，这样可以支持多个npm registry域名\n\n## hosts 文件配置\n\n要让本地请求指向代理服务器，需要修改 hosts 文件。推荐使用[SwitchHosts](https:\u002F\u002Fgithub.com\u002Foldj\u002FSwitchHosts)。但需要注意，大部分系统下，修改Hosts都需要管理员权限，有些系统还需要专门添加可写权限才能修改成功。\n\n```plaintext\n# NPM registry proxy\n10.x.x.x    registry.npmjs.com registry.npmjs.org\n```\n\n## 结语\n\n通过以上配置，我们就可以使用自己的服务器来代理npm包的下载，目前我已经使用了一段时间，下载速度明显提升，推荐有这个问题且不方便用梯子的也尝试一下。\n\n> 本文部分内容由Cursor（AI驱动的代码编辑器）协助编写和润色。\n",null,0,"2026-08-28 04:37:17","published","\u003Cp>最近在家里开发项目的时候，时常碰到npm安装超时。想了一下手上有好多服务器，应该能解决这个问题，于是我搭建了一个代理服务器。\u003C\u002Fp>\n\u003Ch2>技术方案概述\u003C\u002Fh2>\n\u003Cp>npm registry有两个主要地址：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fregistry.npmjs.com\">https:\u002F\u002Fregistry.npmjs.com\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fregistry.npmjs.org\">https:\u002F\u002Fregistry.npmjs.org\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>需要让npm客户端访问这两个域名的时候走自己的服务器，并突破封锁。\u003C\u002Fp>\n\u003Cp>本方案概要：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>使用Nginx搭建反向代理服务器\u003C\u002Fli>\n\u003Cli>自签名SSL证书并设置信任\u003C\u002Fli>\n\u003Cli>使用TailScale VPN实现网络互通\u003C\u002Fli>\n\u003Cli>hosts文件配置域名解析\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>其中TailScale是一个基于WireGuard的现代VPN解决方案，它是本方案中不可或缺的组件，因为它能够帮助我们：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>通过零配置组网快速建立安全通道\u003C\u002Fli>\n\u003Cli>利用 WireGuard 的高性能加密通信确保数据安全\u003C\u002Fli>\n\u003Cli>实现 NAT 穿透，突破网络封锁\u003C\u002Fli>\n\u003Cli>支持多平台部署\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cblockquote>\n\u003Cp>为什么不直接使用梯子：一方面是因为梯子流量有限，安装npm包会消耗大量流量；另一方面是我主要使用浏览器插件来分流，因此梯子没有配置按域名分流，无法针对npm的请求进行分流。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cblockquote>\n\u003Cp>为什么不使用npm镜像：因为通过npm镜像安装的话，lock文件也会使用镜像地址，这样在CI\u002FCD环境中可能会出现新的问题。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2>SSL证书配置与信任\u003C\u002Fh2>\n\u003Cp>为了确保npm客户端信任我们自己搭的反向代理，我们需要配置并信任自签名证书。整个过程分为三步：生成根证书（CA）、生成服务器证书、添加证书信任。\u003C\u002Fp>\n\u003Ch3>生成根证书（CA）\u003C\u002Fh3>\n\u003Cp>这个脚本完成以下工作：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>生成 2048 位的 CA 私钥\u003C\u002Fli>\n\u003Cli>创建证书签名请求（CSR）\u003C\u002Fli>\n\u003Cli>设置基本约束和密钥用途\u003C\u002Fli>\n\u003Cli>生成有效期为10年的CA证书\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cpre>\u003Ccode>#!\u002Fbin\u002Fbash\nset -o errexit\n\n# Generate CA private key\nopenssl genrsa -out ca.key 2048\n\n# Generate CA certificate signing request\nopenssl req -new -key ca.key -out ca.csr -sha256 \\\n    -subj &quot;\u002FC=CN\u002FST=GuangDong\u002FL=Shenzhen\u002FO=Tinkink\u002FOU=Tinkink\u002FCN=tinkink.net&quot;\n\n# Create ca.ext file\necho &quot;basicConstraints=CA:TRUE\nkeyUsage=keyCertSign,cRLSign&quot; &gt; ca.ext\n\n# Generate CA certificate\nopenssl x509 -req -in ca.csr -signkey ca.key -out ca.crt \\\n    -extfile ca.ext -sha256 -days 3650\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>生成服务器证书\u003C\u002Fh3>\n\u003Cp>这个脚本完成以下工作：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>生成服务器私钥\u003C\u002Fli>\n\u003Cli>创建服务器证书签名请求\u003C\u002Fli>\n\u003Cli>配置证书扩展信息，包括多域名支持\u003C\u002Fli>\n\u003Cli>使用之前创建的 CA 证书签发服务器证书\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cpre>\u003Ccode>#!\u002Fbin\u002Fbash\n\n# Generate private key for npm\nopenssl genrsa -out npm.key 2048\n\n# Generate certificate signing request\nopenssl req -new -key npm.key -out npm.csr -sha256 \\\n    -subj &quot;\u002FC=CN\u002FST=GuangDong\u002FL=Shenzhen\u002FO=Tinkink\u002FOU=Tinkink\u002FCN=registry.npmjs.org&quot;\n\n# Create npm.ext file\necho &quot;authorityKeyIdentifier=keyid,issuer\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment\nsubjectAltName=@alt_names\n\n[alt_names]\nDNS.1=registry.npmjs.org\nDNS.2=registry.npmjs.com&quot; &gt; npm.ext\n\n# Generate certificate\nopenssl x509 -req -in npm.csr -CA ca.crt -CAkey ca.key \\\n    -CAcreateserial -out npm.crt -extfile npm.ext -sha256 -days 720\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>证书信任配置\u003C\u002Fh3>\n\u003Cp>生成证书后，需要将 CA 证书（ca.crt）添加到系统的信任存储中：\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Windows\u003C\u002Fstrong>:\u003C\u002Fp>\n\u003Col>\n\u003Cli>双击证书文件\u003C\u002Fli>\n\u003Cli>选择&quot;安装证书&quot; -&gt; &quot;本地计算机&quot;（需要管理员权限）\u003C\u002Fli>\n\u003Cli>选择&quot;受信任的根证书颁发机构&quot;\u003C\u002Fli>\n\u003Cli>也可以使用管理员权限运行 PowerShell 命令：\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode>Import-Certificate -FilePath &quot;ca.crt&quot; -CertStoreLocation Cert:\\LocalMachine\\Root\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>Mac\u003C\u002Fstrong>:\u003C\u002Fp>\n\u003Col>\n\u003Cli>双击证书文件，添加到钥匙串访问\u003C\u002Fli>\n\u003Cli>在钥匙串访问中找到证书，双击展开\u003C\u002Fli>\n\u003Cli>展开&quot;信任&quot;选项，将&quot;使用此证书时&quot;设置为&quot;始终信任&quot;\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>\u003Cstrong>Linux\u003C\u002Fstrong>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sudo cp ca.crt \u002Fusr\u002Flocal\u002Fshare\u002Fca-certificates\u002F\nsudo update-ca-certificates\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Nginx 反向代理配置\u003C\u002Fh2>\n\u003Cp>在服务器上先配置好TailScale VPN，确保本地和服务器在同一个网络中。然后使用以下 Nginx 配置文件：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>server {\n    listen 80;\n    server_name registry.npmjs.com registry.npmjs.org;\n\n    # Redirect all HTTP requests to HTTPS\n    return 301 https:\u002F\u002F$host$request_uri;\n}\n\nserver {\n    listen 443 ssl;\n    server_name registry.npmjs.com registry.npmjs.org;\n\n    ssl_certificate \u002Fetc\u002Fnginx\u002Fssl\u002Fnpm.crt;\n    ssl_certificate_key \u002Fetc\u002Fnginx\u002Fssl\u002Fnpm.key;\n\n    ssl_protocols TLSv1.2 TLSv1.3;\n\n    # Define the DNS resolver\n    resolver 8.8.8.8 8.8.4.4 valid=30s; # You can use Google's public DNS or any resolver you prefer\n    resolver_timeout 5s;\n\n    # Proxy requests to npm registry\n    location \u002F {\n        proxy_pass https:\u002F\u002F$host;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n\n        # Proxy settings to handle large requests and timeouts\n        proxy_read_timeout 90;\n        proxy_connect_timeout 90;\n        proxy_redirect off;\n\n        # Optionally, if you need to handle large response or request sizes\n        client_max_body_size 50M;\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>这里重点说明两个关键配置：\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Ccode>resolver\u003C\u002Fcode>配置用来指定当nginx访问npm registry时的DNS解析服务器，这里使用了Google的公共DNS服务器，如果不设置的话会报错\u003C\u002Fli>\n\u003Cli>\u003Ccode>proxy_pass https:\u002F\u002F$host\u003C\u002Fcode>：使用 \u003Ccode>$host\u003C\u002Fcode> 变量而不是硬编码域名，这样可以支持多个npm registry域名\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2>hosts 文件配置\u003C\u002Fh2>\n\u003Cp>要让本地请求指向代理服务器，需要修改 hosts 文件。推荐使用\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Foldj\u002FSwitchHosts\">SwitchHosts\u003C\u002Fa>。但需要注意，大部分系统下，修改Hosts都需要管理员权限，有些系统还需要专门添加可写权限才能修改成功。\u003C\u002Fp>\n\u003Cpre class=\"shiki\" style=\"background-color:#121212;color:#dbd7caee\" tabindex=\"0\">\u003Ccode># NPM registry proxy\n10.x.x.x    registry.npmjs.com registry.npmjs.org\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>结语\u003C\u002Fh2>\n\u003Cp>通过以上配置，我们就可以使用自己的服务器来代理npm包的下载，目前我已经使用了一段时间，下载速度明显提升，推荐有这个问题且不方便用梯子的也尝试一下。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>本文部分内容由Cursor（AI驱动的代码编辑器）协助编写和润色。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n","\u003Cp>最近在家里开发项目的时候，时常碰到npm安装超时。想了一下手上有好多服务器，应该能解决这个问题，于是我搭建了一个代理服务器。\u003C\u002Fp>\n\u003Ch2>技术方案概述\u003C\u002Fh2>\n\u003Cp>npm registry有两个主要地址：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fregistry.npmjs.com\">https:\u002F\u002Fregistry.npmjs.com\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fregistry.npmjs.org\">https:\u002F\u002Fregistry.npmjs.org\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>需要让npm客户端访问这两个域名的时候走自己的服务器，并突破封锁。\u003C\u002Fp>\n","",{"total":19,"totalRoots":19,"comments":26,"pv":19},[]]