Bug
router.route("/*", "http://<alb-dns>") results in a 502 "Failed to contact the origin" because CloudFront attempts HTTPS:443 instead of HTTP:80.
Reproduction
const router = new sst.aws.Router("MyRouter", { domain: "example.com" });
const service = new sst.aws.Service("MyService", {
cluster,
loadBalancer: {
rules: [{ listen: "80/http", forward: "8080/http" }],
},
});
// Pass the ALB's raw DNS as an http:// URL
const albUrl = service.nodes.loadBalancer.dnsName.apply(
(dns) => `http://${dns}`
);
router.route("/*", albUrl);
The ALB only listens on port 80 (HTTP). CloudFront returns 502 because it tries to connect on HTTPS:443.
Root cause
In the generated CloudFront Function, setUrlOrigin builds the origin object like this:
function setUrlOrigin(urlHost, override) {
const origin = {
domainName: urlHost,
customOriginConfig: { port: 443, protocol: "https", sslProtocols: ["TLSv1.2"] },
originAccessControlConfig: { enabled: false },
};
override = override ?? {};
if (override.protocol === "http") {
delete origin.customOriginConfig;
}
// ...
cf.updateRequestOrigin(origin);
}
When protocol === "http", customOriginConfig is deleted. The expectation is that cf.updateRequestOrigin inherits the placeholder origin's customOriginConfig (which is http-only port 80). However, the presence of originAccessControlConfig: { enabled: false } appears to prevent this inheritance — CloudFront defaults to HTTPS:443 instead.
The KV store metadata confirms the route is correctly stored:
{
"host": "my-alb-1234567890.us-east-2.elb.amazonaws.com",
"origin": { "protocol": "http" }
}
And the placeholder origin is correctly configured:
{
"CustomOriginConfig": {
"HTTPPort": 80,
"OriginProtocolPolicy": "http-only"
}
}
But the ALB gets an HTTPS connection attempt on 443 → connection refused → 502.
Suggested fix
Don't include originAccessControlConfig for non-OAC origins. For HTTP custom origins it serves no purpose and interferes with customOriginConfig inheritance:
function setUrlOrigin(urlHost, override) {
const origin = { domainName: urlHost };
if (!override || override.protocol !== "http") {
origin.customOriginConfig = { port: 443, protocol: "https", sslProtocols: ["TLSv1.2"] };
}
if (override?.connectionAttempts) origin.connectionAttempts = override.connectionAttempts;
if (override?.timeouts) origin.timeouts = override.timeouts;
if (override?.originAccessControlConfig) {
origin.originAccessControlConfig = override.originAccessControlConfig;
}
cf.updateRequestOrigin(origin);
}
Workaround
Monkeypatch cf.updateRequestOrigin via edge.viewerRequest.injection to strip the empty originAccessControlConfig before it reaches CloudFront:
new sst.aws.Router("MyRouter", {
domain: "example.com",
edge: {
viewerRequest: {
injection: `
const _update = cf.updateRequestOrigin.bind(cf);
cf.updateRequestOrigin = (o) => {
if (o.originAccessControlConfig && !o.originAccessControlConfig.enabled) delete o.originAccessControlConfig;
_update(o);
};`,
},
},
});
Environment
- SST: v4.7.3
- AWS provider: 7.20.0
- Region: us-east-2
- CloudFront Function runtime: cloudfront-js-2.0
Bug
router.route("/*", "http://<alb-dns>")results in a 502 "Failed to contact the origin" because CloudFront attempts HTTPS:443 instead of HTTP:80.Reproduction
The ALB only listens on port 80 (HTTP). CloudFront returns 502 because it tries to connect on HTTPS:443.
Root cause
In the generated CloudFront Function,
setUrlOriginbuilds the origin object like this:When
protocol === "http",customOriginConfigis deleted. The expectation is thatcf.updateRequestOrigininherits the placeholder origin'scustomOriginConfig(which ishttp-onlyport 80). However, the presence oforiginAccessControlConfig: { enabled: false }appears to prevent this inheritance — CloudFront defaults to HTTPS:443 instead.The KV store metadata confirms the route is correctly stored:
{ "host": "my-alb-1234567890.us-east-2.elb.amazonaws.com", "origin": { "protocol": "http" } }And the placeholder origin is correctly configured:
{ "CustomOriginConfig": { "HTTPPort": 80, "OriginProtocolPolicy": "http-only" } }But the ALB gets an HTTPS connection attempt on 443 → connection refused → 502.
Suggested fix
Don't include
originAccessControlConfigfor non-OAC origins. For HTTP custom origins it serves no purpose and interferes withcustomOriginConfiginheritance:Workaround
Monkeypatch
cf.updateRequestOriginviaedge.viewerRequest.injectionto strip the emptyoriginAccessControlConfigbefore it reaches CloudFront:Environment