Can an origin rule redirect based on incoming port?
Origin Rules allows you to override the destination port, but is it possible to create a rule that filters based on the incoming port? If so, how, as I can't find an option to do this.
The configuration I want to create is to have all traffic incoming on one URL, but if the traffic is on port 80 or 443 for HTTP(S) traffic then it should be directed to an R2 bucket, and if the traffic is sent on an arbitrary port (25565) then it should be directed to an IP address (a web server). What would be the best way to achieve this? I do not wish for the HTTP(S) traffic to be redirected to the web server and then back to R2, the redirection should happen using Cloudflare rules.
Any help would be greatly appreciated, thank you.
6 Replies
but is it possible to create a rule that filters based on the incoming port?Strictly speaking, yes. It's not part of the expression builder, but if you click the
Edit Expression
button, you can manually enter one in.
The field you're looking for is cf.edge.server_port
, ex:
(http.host eq "my-subdomain.example.com" and cf.edge.server_port eq 2096)
it should be directed to an R2 bucketThat won't work with R2 Custom Domains, they take over the entire hostname, and only Enterprise could override the DNS Record in Origin Rules (and I'm not sure that would even work with the r2 bucket bound to the hostname) You could use a worker bound to the bucket and directly handle the port in there and fetch as needed.
sent on an arbitrary port (25565)This would also only work on Cloudflare's supported Network ports: https://developers.cloudflare.com/fundamentals/reference/network-ports/ You can rewrite the traffic to any port outgoing though, but Cloudflare only has those ports open for clients to connect to. Does your setup have a greater underlying purpose or need? It seems pretty weird, why not just use a separate subdomain for both?
I see, thank you.
Ultimately I think subdomains would probably be the better option, I just wanted to avoid using them if I could. The initial intention was that the arbitrary port would be running a video game server, and if a user decided to instead visit the domain using a web browser, they'd be served a static image, which is what the R2 bucket would contain. I wasn't sure if rules could override the "R2 taking over a domain" thing, and I think the "only certain ports are open" thing is something I'd encountered before and just forgotten about because I'd had proxying off in the past. It's a shame that I can't implement my original intention but a subdomain probably makes a lot more sense, thank you for your help and explaining everything :)
The initial intention was that the arbitrary port would be running a video game serverWell that wouldn't work for different reasons as well. When you have the Cloudflare Proxy enabled, Cloudflare responds to DNS Queries with a few Anycast Edge IPs from their pool, shared among a lot of other customers. Part of an HTTP/HTTPS connection is the SNI or Host Header which is used to identify which website the request is for - even when the IP is shared. This is part of HTTP / TLS Protocol. The same can't be said for arbitrary traffic, like for game servers. Cloudflare would have no idea which website it is bound for (all they have is src ip, src port, dst port, dst ip, not enough when the IPs are shared), and just throw it out. Essentially, the proxy only supports HTTP Traffic. Cloudflare does have Spectrum, their arbitrary tcp/udp proxying product, and you could use it like that... with Enterprise, as an addon, probably out of reach sadly.
thank you for your help and explaining everything 🙂Of course, no problem. You could still just have an unproxied record pointing at your gameserver, and if you have control over it, run a simple web server on it serving an image, but that would also open you up for other attacks (forgot to state, the reason why Spectrum works is because it assigns you a unique IP rather then shared ones, which is also one of the reasons why it is expensive with rising ipv4 costs)
The reason why I don't just send everything to the web server to deal with is because I'm already hosting HTTPS on the web server. example1.com receives HTTP(S) traffic and is proxied through cloudflare to the web server. I want to use the same web server to proxy arbitrary game server traffic for example2.com, but I'm not smart enough to figure out how to host HTTP(S) traffic for two websites from the same server. So the idea was, make sure that no HTTP(S) traffic for example2.com gets through to the web server, so then it doesn't clash with the config for example1.com.
So I think what I'm probably going to end up doing is:
1. Set up an unproxied DNS record for gameserver.example2.com that points to the web server.
2. Set up an R2 bucket to handle HTTP(S) traffic on the example2.com.
At that point I don't know what I would do to prevent HTTP(S) traffic on gameserver.example2.com from receiving the response intended for example1.com, but I guess it's not too much of an issue and maybe there's a simple way to prevent that within nginx... As for the security risk thing, I don't think it will be an issue since the game server will be handling a very small amount of traffic and the web server is only proxying it to another server anyway.
nginx server_name directive and server blocks would be what you want to use:
https://nginx.org/en/docs/http/server_names.html
They both would allow you to have two different websites on the same server ip/port, and also if configured right, would reject any traffic not bound for a server_name that is configured (this is using the same Host Header/ SNI (Server Name identifier) I mentioned above). You'd also need/want the proper certificates for both most likely, which can be accomplished using certbot
Nginx is super popular and there's a lot of tutorials out there, and there's also a config generator you can use: https://www.digitalocean.com/community/tools/nginx, which has built in certbot / let's encrypt support
I'm already using certbot for the first website, so that's fine
I'll take a look at the documentation for that, thank you