资讯动态

Python后端部署排障10:端口能连,为什么HTTPS仍然拒绝连接

发布时间:2026/10/30 2:18:45 来源:尧图企业网站定制
Python后端部署排障10端口能连为什么HTTPS仍然拒绝连接一次curl失败可能发生在HTTP之前。TCP握手成功只能说明网络可达TLS还要协商加密参数、验证对方身份并建立可信连接。很多初学者遇到证书错误就加-k得到200后认为问题解决实际上绕过了本来要验证的身份条件。本课建立独立实验CA分别证明正确连接、主机名错误和缺少信任根三种情况。E09答案代理恢复之后再谈TLS上一课的错误上游实验由labctl集中管理故障容器和配置恢复也在同一处记录。答案不复制一套任意修改Nginx的逻辑而是调用真实演练入口再独立请求ready确认恢复。完整故障与恢复信息随JSON输出不依靠截图上一个模糊的绿色图标判断。lessons/10/answer_previous.pyE09: reproduce an invalid upstream and prove recovery through the real edge.importjsonimportsubprocessimportsysfrompathlibimportPathfromurllib.requestimportProxyHandler,build_opener ROOTPath(__file__).resolve().parents[2]deflab(*args):resultsubprocess.run([sys.executable,ops/labctl.py,*args],cwdROOT,capture_outputTrue,textTrue,timeout60,checkTrue,)returnjson.loads(result.stdout)defmain():statelab(status)reportlab(drill,nginx-502)assertreport[status]PASS,reportassertreport[evidence][observed_status]502,reportwithbuild_opener(ProxyHandler({})).open(state[http_url]/ready,timeout5)asresponse:assertresponse.status200assertjson.load(response)[status]readyprint(json.dumps({status:PASS,fault_and_recovery:report},indent2))if__name____main__:main()执行python3 lessons/10/answer_previous.py之前实验环境应已启动。若HTTP入口尚未恢复先解决代理问题不要同时改证书、上游和端口一次改变多个层次会让成功后也说不清真正原因。分层排查的价值就在于每次只用足够的证据缩小范围。证书、私钥和CA各自承担什么服务器证书是一份带签名的身份声明其中包含公钥、有效期、用途和域名。私钥用于证明服务器持有与公钥配对的秘密不能因为“只是测试证书”就跟着文章或ZIP公开。CA用自己的签名让客户端能够验证服务器证书来源客户端信任的是CA证书所代表的根而不是任何声称由某CA签发的文本。本实验生成专用CA与叶证书只在单次运行内使用。CA有效期七天服务器证书两天便于明确它们不是长期生产材料。服务器证书包含subjectAltNameDNS:quoteops.test和serverAuth用途。现代客户端检查域名应依赖SAN不能仅靠证书主题里的CN“看着差不多”。通配符、多个SAN和IP地址SAN各有规则本课只用一个精确DNS名称降低变量数量。deploy/make_tls.pyGenerate an isolated lab CA and SAN leaf certificate with host OpenSSL.importargparseimportosimportshutilimportsubprocessfrompathlibimportPathdefgenerate(output:Path)-None:ifos.name!posix:raiseSystemExit(Generate lab TLS on Linux so private-key modes are enforced)ifshutil.which(openssl)isNone:raiseSystemExit(Host openssl is required)outputoutput.resolve()output.mkdir(parentsTrue,exist_okTrue,mode0o700)ifany(output.iterdir()):raiseSystemExit(fRefusing to overwrite nonempty TLS directory:{output})output.chmod(0o700)old_umaskos.umask(0o077)try:extensionsoutput/server.extextensions.write_text(basicConstraintscritical,CA:FALSE\nkeyUsagecritical,digitalSignature,keyEncipherment\nextendedKeyUsageserverAuth\nsubjectAltNameDNS:quoteops.test\n,encodingascii,)commands[[req,-x509,-newkey,rsa:2048,-nodes,-sha256,-days,7,-keyout,ca.key,-out,ca.crt,-subj,/CNQuoteOps Lab CA,-addext,basicConstraintscritical,CA:TRUE,-addext,keyUsagecritical,keyCertSign,cRLSign,],[req,-new,-newkey,rsa:2048,-nodes,-sha256,-keyout,server.key,-out,server.csr,-subj,/CNquoteops.test,],[x509,-req,-in,server.csr,-CA,ca.crt,-CAkey,ca.key,-CAcreateserial,-out,server.crt,-days,2,-sha256,-extfile,server.ext,],[verify,-CAfile,ca.crt,-verify_hostname,quoteops.test,server.crt,],]forcommandincommands:resultsubprocess.run([openssl,*command],cwdoutput,textTrue,capture_outputTrue)ifresult.returncode:raiseRuntimeError(fopenssl failed:{result.stderr.strip()})fornamein(ca.crt,server.crt):(output/name).chmod(0o644)(output/server.key).chmod(0o600)# The runtime has no CA signing key; a new experiment generates a new CA.fornamein(ca.key,ca.srl,server.csr,server.ext):(output/name).unlink(missing_okTrue)finally:os.umask(old_umask)print(fTLS files ready:{output})defmain()-None:parserargparse.ArgumentParser(description__doc__)parser.add_argument(--output,requiredTrue,typePath)generate(parser.parse_args().output)if__name____main__:main()脚本以参数数组调用宿主OpenSSL不拼接shell命令也不要求Python第三方加密库。它拒绝覆盖非空目录先用严格umask创建密钥再把公开证书设为644、服务器私钥设为600。签发完成后删除CA私钥、序列文件和中间CSR只保留运行所需的三份文件。这意味着该实验CA之后不能继续签发新叶证书重新实验会生成新CA客户端也要换用相应的公开根。运行目录本身为700Nginx root master负责读取证书和私钥worker降权为nginx处理请求。这个安排与应用进程UID10001无关不需要把私钥改成所有用户可读。容器挂载只读应用镜像也不包含证书。是否只读控制修改能力文件权限控制读取能力两者需要同时理解。DNS、连接地址、SNI和验证名称不能混在一起浏览器请求https://quoteops.test:端口时通常先解析域名再连接得到的地址TLS握手携带SNI告诉服务器请求哪个站点客户端同时按URL里的主机名检查证书。实验不修改宿主hosts和公共DNS而用curl的--resolve临时指定这一次请求的地址映射。这样URL仍然是quoteops.testSNI和主机名校验仍然使用正确域名连接却落到127.0.0.1的实验端口。直接请求https://127.0.0.1:端口再手工加一个Host头并不等价。Host头属于TLS建立后的HTTP消息不能替代握手时的SNI和证书名称验证。我们的SAN没有127.0.0.1这个IP地址客户端理应拒绝这种身份不匹配。若为了让它通过而关闭验证就失去了实验需要证明的安全属性。下面脚本从状态文件读取真实端口与CA位置避免读者把上一次的随机端口复制进本次实验。它只执行正确连接这一种情况完整三向答案留到下一课。importjsonimportsubprocessimportsysfromurllib.parseimporturlsplit statejson.loads(subprocess.check_output([sys.executable,ops/labctl.py,status],textTrue,timeout60))porturlsplit(state[https_url]).port subprocess.run([curl,--noproxy,*,--fail,--show-error,--connect-timeout,2,--max-time,5,--resolve,fquoteops.test:{port}:127.0.0.1,--cacert,state[ca_file],fhttps://quoteops.test:{port}/ready,],checkTrue,timeout10)--noproxy *避免机器上已有代理变量把个人实验请求送去别处。--cacert仅为这一条curl进程提供根证书不修改全系统信任仓库。正确调用应完成证书验证并得到ready响应退出码为0。注意成功证据有两个部分TLS校验通过以及之后的HTTP业务检查通过只有其中一个还不能说明整条请求链路可用。同一个错误码也可能有不同原因curl常用退出码60表示证书验证失败的类别主机名不匹配和不受信任的CA都可能归在这里。因此不能只把“60”记成一个固定故障应保留stderr说明并检查证书SAN、颁发者、有效期以及使用的CA路径。服务器可能返回了别的站点证书客户端也可能用了上一轮实验留下的CA文件它们都需要不同修复。过期是另一种时间条件。客户端验证时看当前时钟是否在证书有效区间宿主时间明显错误也可能表现成“尚未生效”或“已过期”。本课不调整宿主时钟来造故障避免影响其他服务。需要检查时用OpenSSL读取notBefore和notAfter再对照UTC时间。续期要替换正确的证书和私钥、测试配置、reload并重新校验不能只更新文件名。对不受信任的本地CA正确操作是让当前客户端显式信任本次公开CA证书对主机名不匹配正确操作是使用证书覆盖的域名或重新签发包含正确SAN的证书。两者都不需要关闭验证。证书链问题还可能来自中间证书缺失在公网部署中应根据服务端发送链和客户端信任根逐段核对本实验的根直接签发叶证书链条更短。TLS终止后的边界仍然存在本课TLS在edge终止edge到应用使用同一受控Docker网络中的HTTP。这是教学部署的边界不能由“浏览器出现锁图标”推导出内部每一跳都加密。若业务要求跨主机加密、双向认证或更严格隔离需要单独设计内部传输和证书生命周期。公网证书签发、自动续期、域名控制权和密钥管理也都超出这个两天有效期的实验流程。SSH隧道只改变如何到达服务器回环端口不改变客户端应该检查的域名。隧道另一端仍应使用URL中的quoteops.test与显式CA必要时让--resolve指向隧道本地监听地址。把隧道连通与TLS验证分开验收才能识别究竟是SSH转发错误、端口错误还是证书错误。读取证书时应该看哪几项OpenSSL的证书查看功能不需要私钥就能显示主题、签发者、序列号、有效期和扩展。首先确认文件真的是服务器正在使用的那一份再检查SAN是否覆盖URL主机名extendedKeyUsage是否允许服务端认证最后核对签发者与客户端信任根。证书文件在磁盘上更新了但master未reload时客户端可能仍看到内存里的旧材料因此从真实入口观察证书也很有必要。私钥与证书不匹配通常会使Nginx配置测试或加载失败与客户端不信任CA处在不同位置。前者应检查成对材料和文件读取权限后者应检查客户端信任来源把server.key权限放宽不会修复客户端的信任链。密钥损坏、证书过期、域名不匹配也不应该共享一个“重签试试”的盲目操作各自有可以先读取的证据。浏览器与curl可能使用不同的信任仓库或代理设置一个通过不保证另一个必然通过。课程用curl显式指定CA和地址映射目的就是减少这些环境差异。若后来需要浏览器体验应单独记录如何信任实验根以及如何撤销不能把个人实验CA安装到整台共享服务器的系统仓库来让脚本方便通过。证书续期验证也应保持原来的成功与失败对照正确主机名通过错误主机名继续失败未知CA继续失败。只确认新证书日期变长却没有验证错误身份会被拒绝无法证明校验仍然启用。这样的负向检查同样适用于后面的坏候选发布系统在不满足条件时拒绝操作是合同的一部分。最后演练报告可以保存公开证书的指纹、有效期和错误摘要但不应保存私钥文本。即使server.key只有两天有效也应跟随本次runtime清理ZIP只交付生成脚本和公开验证证据。可复现意味着读者能生成自己的实验材料而不是所有读者共用同一份秘密。E10做三次请求而不是加一个开关第一次使用正确域名、本次CA和正确端口要求退出0且ready成功。第二次仍信任CA但把URL主机名换成wrong.quoteops.test同时用resolve连接同一入口要求名称校验失败。第三次恢复正确主机名去掉专用CA要求信任校验失败。保留每次退出码与错误摘要任何一条命令都不能包含-k或--insecure。下一课提供完整答案并把健康检查放回进程生命周期里证书和代理都成功之后为什么/health是200而/ready仍然可能是503。参考curl手册、curl证书验证、OpenSSL req、OpenSSL verify、Nginx HTTPS配置。课程目录《Linux、网络与后端部署排障从“接口能跑”走到“服务能维护”》 · 上一篇第09篇 · 下一篇第11篇

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑