{"record":{"id":"4a605383c6e9e721","repo":"vllm-project/vllm","slug":"ssl-certfile-is-required-to-enable-tls-ssl-ke","errorCode":null,"errorMessage":"--ssl-certfile is required to enable TLS; --ssl-keyfile/--ssl-ca-certs/--ssl-cert-reqs/--ssl-ciphers cannot be used without it","messagePattern":"--ssl-certfile is required to enable TLS; --ssl-keyfile/--ssl-ca-certs/--ssl-cert-reqs/--ssl-ciphers cannot be used without it","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust/src/server/src/config.rs","lineNumber":135,"sourceCode":"    /// (combined PEM).\n    pub key_file: Option<String>,\n    /// PEM CA bundle used to verify client certificates (mTLS). Required when\n    /// `cert_reqs` is non-zero.\n    pub ca_certs: Option<String>,\n    /// Client-certificate requirement, mirroring Python's `ssl.CERT_*`:\n    /// 0 = none, 1 = optional, 2 = required.\n    pub cert_reqs: i32,\n    /// OpenSSL cipher string for TLS 1.2 and below, mirroring Python's\n    /// `ssl.set_ciphers`. `None` keeps the forward-secret AEAD default.\n    pub ciphers: Option<String>,\n}\n\nimpl TlsConfig {\n    /// Structurally validate the TLS arguments; the cert/key material is parsed\n    /// later, when the OpenSSL context is built.\n    pub fn validate(&self) -> Result<()> {\n        if self.cert_file.is_none() {\n            bail!(\n                \"--ssl-certfile is required to enable TLS; \\\n                 --ssl-keyfile/--ssl-ca-certs/--ssl-cert-reqs/--ssl-ciphers \\\n                 cannot be used without it\"\n            );\n        }\n        if !matches!(self.cert_reqs, 0..=2) {\n            bail!(\n                \"--ssl-cert-reqs must be 0 (none), 1 (optional), or 2 (required), got {}\",\n                self.cert_reqs\n            );\n        }\n        if self.cert_reqs != 0 && self.ca_certs.is_none() {\n            bail!(\n                \"--ssl-ca-certs is required when --ssl-cert-reqs is {} \\\n                 (client certificate verification)\",\n                self.cert_reqs\n            );\n        }","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/rust/src/server/src/config.rs#L117-L153","documentation":"Thrown by TlsConfig::validate() when any TLS option (--ssl-keyfile, --ssl-ca-certs, --ssl-cert-reqs, --ssl-ciphers) is set but --ssl-certfile is not. The Rust frontend mirrors Python uvicorn's ssl_* arguments and treats the server certificate as the switch that enables TLS; structural validation runs at startup, before the OpenSSL context is built.","triggerScenarios":"Configuring e.g. --ssl-keyfile server.key --ssl-cert-reqs 2 without also passing --ssl-certfile server.pem. Also triggered by setting only --ssl-ciphers or only --ssl-ca-certs. Any TlsConfig with cert_file == None fails validate() unconditionally, even if all other fields are defaults.","commonSituations":"Migrating a deployment where the cert/key live in a combined PEM and only the key flag was carried over; CI pipelines that template TLS flags conditionally; combining-peer-cert (mTLS) setup where --ssl-ca-certs was added first.","solutions":["Add --ssl-certfile pointing to your PEM certificate chain: --ssl-certfile server.pem --ssl-keyfile server.key.","If the PEM contains both cert and key, --ssl-certfile alone is sufficient per the TlsConfig docs.","If you did not intend to enable TLS, remove all --ssl-* flags (including --ssl-ciphers and --ssl-cert-reqs defaults set by your launcher).","Verify flag ordering in your unit/systemd file — a missing value can silently consume the next flag."],"exampleFix":"# before\nvllm serve model --ssl-keyfile server.key --ssl-ca-certs ca.pem\n\n# after\nvllm serve model --ssl-certfile server.pem --ssl-keyfile server.key --ssl-ca-certs ca.pem","handlingStrategy":"validation","validationCode":"fn tls_config_complete(cert: &Option<PathBuf>, others_set: bool) -> bool {\n    !others_set || cert.is_some()\n}","typeGuard":"fn tls_is_structurally_valid(tls: &Option<TlsConfig>) -> bool {\n    match tls {\n        None => true,\n        Some(t) => t.cert_file.is_some(),\n    }\n}","tryCatchPattern":"match config.tls.as_ref().map(|t| t.validate()) {\n    Some(Err(e)) => eprintln!(\"TLS config rejected: {e}\"),\n    _ => {}\n}","preventionTips":["Treat --ssl-certfile as the TLS on-switch: set it first, then other --ssl-* flags.","Write TLS flags as one block in the unit file so they move together.","Run a preflight that calls Config::validate() before exec'ing the server."],"tags":["configuration","tls","ssl","security","rust","vllm","startup"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}