I try to make a Rust Actix TLS web server.
Project layout
.
├── .env
├── Cargo.lock
├── Cargo.toml
├── certs
│ ├── cert.pem
│ └── key.pem
└── src
├── api_error.rs
├── handlers.rs
└── main.rs
.env
RUST_LOG=debug
PORT=443
CERTIFICATE_PATH=certs/cert.pem
PRIVATE_KEY_PATH=certs/key.pem
Cargo.toml
[package]
name = "https-test"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-web = { version = "4.3.1", features = ["openssl"] }
openssl = { version = "0.10.54", features = ["v110"], optional = true }
anyhow = "1.0.72"
log = "0.4.19"
env_logger = "0.10.0"
dotenvy = "0.15.7"
main.rs
mod api_error;
mod handlers;
use anyhow::{anyhow, Result};
use log::info;
#[actix_web::main]
async fn main() -> Result<()> {
dotenvy::dotenv()?;
env_logger::init();
info!("Starting server");
let port = std::env::var("PORT")?.parse::<u16>()?;
let server = actix_web::HttpServer::new(|| {
actix_web::App::new()
.wrap(actix_web::middleware::Logger::default())
.service(actix_web::web::scope("/api/v1").configure(handlers::config_app))
});
let server = server.bind_openssl(("0.0.0.0", port), {
info!("Using TLS");
let mut builder = openssl::ssl::SslAcceptor::mozilla_intermediate(openssl::ssl::SslMethod::tls())
.unwrap();
let private_key_path = std::env::var("PRIVATE_KEY_PATH")?;
let certificate_path = std::env::var("CERTIFICATE_PATH")?;
builder
.set_private_key_file(private_key_path, openssl::ssl::SslFiletype::PEM)
.unwrap();
builder
.set_certificate_chain_file(certificate_path)
.unwrap();
builder
})?;
server.run().await.map_err(|e| anyhow!(e))
}
handlers.rs
use crate::api_error::ApiError;
pub fn config_app(cfg: &mut actix_web::web::ServiceConfig) {
cfg.service(actix_web::web::resource("/").route(actix_web::web::get().to(index)));
}
async fn index() -> Result<actix_web::HttpResponse, ApiError> {
log::debug!("Hitting `index`");
Ok(actix_web::HttpResponse::Ok().body("Hello world !"))
}
Note: the certificate is self-signed with a CA that I generated. I put the root CA in my system's trusted CA so I don't get the "Untrusted certificate" error in the browser every time.
When running the server, I get the expected logs:
$ cargo run --release
[INFO https-test] Starting server
[INFO actix_server::builder] starting 10 workers
[INFO actix_server::server] Actix runtime found; starting in Actix runtime
Then on the browser, I go to https://localhost/
, my browser can't connect to the server, in the logs I get:
[ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided
[ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided
[ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided
[ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided
[ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided
[ERROR actix_http::h1::dispatcher] stream error: request parse error: invalid Header provided
The issue seems to be related to the HTTP/1.1 parser detecting an invalid header in the request. This can happen due to various reasons, such as:
Let's explore some troubleshooting steps:
Make sure your SSL/TLS certificates are properly loaded, and the path is correct. Double-check if you can use openssl
CLI to inspect them:
openssl x509 -in certs/cert.pem -text -noout
openssl rsa -check -in certs/key.pem
Ensure that CERTIFICATE_PATH
and PRIVATE_KEY_PATH
environment variables are correctly loaded and pointing to the correct paths.
You can use a tool like tcpdump
or Wireshark to capture the raw packets between the client and server. This can provide further clues about what's wrong with the headers:
sudo tcpdump -i lo0 'port 443' -w capture.pcap
Instead of a browser, try using curl
to see if the error still persists. Make sure to use the -k
flag to accept the self-signed certificate.
curl -k https://localhost:443/api/v1/
Modify your .env
file or directly set RUST_LOG
to trace
to get even more detailed logs. This can provide clues into what part of the request is causing the error.
Try running the server without SSL/TLS to see if the issue is actually related to SSL/TLS or something else. If it works fine without SSL, it's likely an issue with your SSL configuration.
Let me know which step gives you more information or if you have further questions.