Summary
Using outboundByHost with interceptHttps = true appears to delete cookies that has been set using Set-Cookie, from the response that has been sent from the outboundBYHost handler. As a result when a response is send back from the container it is not including the cookies. If multiple Set-Cookie header present then also it is not sending the cookie .
Github Repo for reproducible code - https://github.com/RahiReja/egress-tests
Environment
- Package: @cloudflare/containers@0.3.3
- Wrangler: 4.81.0
- Worker compatibility date: 2026-02-06
- enableInternet = true
- interceptHttps = true
Minimal shape of the setup
export class EgressTestContainer extends Container {
defaultPort = 8080;
sleepAfter = '3m';
enableInternet = false;
interceptHttps = true;
// allowedHosts gates everything: only these hosts can reach outbound/internet.
// 'by-host.com' is included so the outboundByHost handler can run.
allowedHosts = ['allowed.com', 'by-host.com', '*.globtest.com'];
deniedHosts = ['denied.com'];
constructor(ctx: any, env: any) {
super(ctx, env);
this.entrypoint = ['node', 'server.js'];
this.envVars = {
NODE_EXTRA_CA_CERTS: '/etc/cloudflare/certs/cloudflare-containers-ca.crt',
};
}
}
EgressTestContainer.outboundByHost = {
'by-host.com': (_req: Request) => {
const res = new Response('outboundByHost: by-host.com');
res.headers.append('Set-Cookie', 'test1=by-host1; Path=/');
res.headers.append('Set-Cookie', 'test2=by-host2; Path=/');
console.log(res.headers.getAll('Set-Cookie')); // Logs both cookies
return res;
},
'*.globtest.com': (req: Request) => {
return new Response('outboundByHost glob: ' + new URL(req.url).hostname);
},
};
EgressTestContainer.outbound = (req: Request) => {
return new Response('catch-all: ' + new URL(req.url).hostname);
};
export default {
async fetch(
request: Request,
env: { CONTAINER: DurableObjectNamespace<EgressTestContainer> }
): Promise<Response> {
try {
const url = new URL(request.url);
const id = url.searchParams.get('id') || 'singleton';
const container = getContainer(env.CONTAINER, id);
if (url.pathname === '/proxy') {
return await container.containerFetch(request);
}
if (url.pathname === '/proxy_https') {
const res = await container.containerFetch(request);
// return await container.containerFetch(request);
console.log('Handler result:', res);
return res;
}
if (url.pathname === '/config/deny-host') {
const hostname = url.searchParams.get('hostname');
if (!hostname) {
return new Response('hostname is required', { status: 400 });
}
await container.denyHost(hostname);
return new Response('OK');
}
if (url.pathname === '/destroy') {
await container.destroy();
return new Response('Container killed');
}
if (url.pathname === '/status') {
const state = await container.getState();
return new Response(JSON.stringify(state, null, 2));
}
return new Response('Not Found');
} catch (e) {
console.error('Worker fetch error:', e);
return new Response(`Worker error: ${e instanceof Error ? e.message : String(e)}`, {
status: 500,
});
}
},
};
Container Code
import { createServer, get } from 'http';
import { get as httpsGet } from 'https';
const server = createServer(function (req, res) {
const url = new URL(req.url, 'http://localhost:8080');
// Outbound HTTP proxy: the container makes an HTTP request to the given host.
const proxyTarget = url.searchParams.get('proxy');
if (proxyTarget) {
get('http://' + proxyTarget, proxyRes => {
let body = '';
proxyRes.on('data', chunk => {
body += chunk;
});
proxyRes.on('end', () => {
res.writeHead(proxyRes.statusCode, { 'Content-Type': 'text/plain' });
res.end(body);
});
}).on('error', err => {
res.writeHead(520, { 'Content-Type': 'text/plain' });
res.end('proxy error: ' + err.message);
});
return;
}
// Outbound HTTPS proxy: uses NODE_EXTRA_CA_CERTS (set via env) to trust
// the Cloudflare containers CA for intercepted HTTPS.
const proxyHttpsTarget = url.searchParams.get('proxy_https');
if (proxyHttpsTarget) {
httpsGet('https://' + proxyHttpsTarget, proxyRes => {
let body = '';
proxyRes.on('data', chunk => {
body += chunk;
});
proxyRes.on('end', () => {
res.writeHead(proxyRes.statusCode, { 'Content-Type': 'text/plain' });
res.end(body);
});
}).on('error', err => {
res.writeHead(520, { 'Content-Type': 'text/plain' });
res.end('proxy_https error: ' + err.message);
});
return;
}
res.writeHead(200, {
'Content-Type': 'text/plain',
'Set-Cookie': ['cookie1=value1; Path=/', 'cookie2=value2; Path=/'],
});
res.end('Hello from egress test container');
});
server.listen(8080, function () {
console.log('Egress test server listening on port 8080');
});
process.on('SIGTERM', () => {
server.close(() => {
process.exit(0);
});
});
This code is identical to the GitHub Container Package example in the egress-tests directory with some modifications.
In the server.js file the proxyHttpsTarget is set to include a Set-Cookie header and the outboundByHost handler has been modified to add two cookie headers. In the index.ts file the /proxy_https route checks the response to verify the integrity of the cookies.
Expected behavior
The cookies added in the outbound handler must be present in the /proxyhttps response. If a fetch request is made in the outbound handler and the response contains multiple set-cookie values, these must be passed to the /proxyhttps response.
Summary
Using
outboundByHostwithinterceptHttps = trueappears to delete cookies that has been set using Set-Cookie, from the response that has been sent from theoutboundBYHosthandler. As a result when a response is send back from the container it is not including the cookies. If multiple Set-Cookie header present then also it is not sending the cookie .Github Repo for reproducible code - https://github.com/RahiReja/egress-tests
Environment
Minimal shape of the setup
Container Code
This code is identical to the GitHub Container Package example in the egress-tests directory with some modifications.
In the server.js file the proxyHttpsTarget is set to include a Set-Cookie header and the outboundByHost handler has been modified to add two cookie headers. In the index.ts file the /proxy_https route checks the response to verify the integrity of the cookies.
Expected behavior
The cookies added in the outbound handler must be present in the /proxyhttps response. If a fetch request is made in the outbound handler and the response contains multiple set-cookie values, these must be passed to the /proxyhttps response.