Is it appropriate for Rocket to try to bind to port 80 by default in production mode? A normal user can't test their app configuration via ROCKET_ENV=prod cargo run because they can't bind to the privileged port. I understand it's trivial to change the port via ROCKET_PORT, but why should this be necessary when running Rocket on port 80 is uncommon (except maybe in a Docker container). I think most deployments would be behind something like nginx/varnish which themselves would be bound on port 80.
$ ROCKET_ENV=prod rustup run nightly cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `/Users/benw/Projects/rocket/target/debug/hello_world`
Warning: environment is 'production', but no `secret_key` is configured
Error: Rocket failed to launch due to an I/O error.
thread 'main' panicked at 'Permission denied (os error 13)', /Users/benw/Projects/rocket/lib/src/error.rs:204
note: Run with `RUST_BACKTRACE=1` for a backtrace.
It's also unfriendly and ambiguous why Rocket thread 'main' panicked at 'Permission denied (os error 13)', unless you know that it's because you can't bind to port 80. Wouldn't it be more appropriate to just have standard rocket port (8000) for all the envs? And then change to the uncommon port 80 as needed.
A normal user _shouldn't_ be able to run the app in production mode. That's what staging is for. Why does the normal user / developer have production database access?
I'd say that the docker container environment is proving to be the common environment for new deployments.
@mehcode The staging env mode also tries to bind to port 80. I think this is incorrect assumption that Rocket is making. Configuring binding to a privileged port is the sysadmin's job, which they would prefer to be explicit with ROCKET_PORT=80, if that's appropriate for their stack.
I think that rocket should just have standard port 8000 regardless of env. Also I think the whole built-in notion of "production", "staging", "development" environments is flawed. 12factor via environment should be the correct way to configure an app.
In addition to the comment above, I would argue that even if docker is the common environment now, we shouldn't be using defaults that only work for a docker environment. Port 8000 works both inside and outside of docker.
I can see the argument here. I'm all for it.
@benwilber With #318 you could use config-rs to easily implement config like that.
Port 80 should just be avoided in general to avoid running the application as a privileged user. If you want it to respond on port 80 either deploy behind a reverse proxy or do port masquerading at the firewall.
I am rather confused as to what's being argued here.
Is it that Rocket shouldn't default stage and prod environments to port 80? If so, well, okay. It just doesn't really matter. As you suggest, that port will probably be changed. So, if that's the case, why does the default matter? Port 80 is the canonical web server port. That's the only reason it's the default port on stage/prod. Defaults are fallbacks. Change them to your liking.
Or is it that the "built-in notion of [environments] is flawed" and that "12factor via environment" is the "correct way" to go? If you feel that way, then feel free to ignore dev/stage/prod and do all your configuration via environment variables. Rocket lets you do that _right now_ with no fuss; everything can be configured via the environment! There's no need for an external library.
Or is that the error message is "unfriendly and ambiguous" when binding fails? I think it's neither. Sure, it doesn't directly tell you that an unprivileged user attempted to bind to an privileged port, but it's not far off from that. I don't think we have enough information to improve the error message. But, if you want to take a crack at improving, please do! I'm all for having the best error messages.
All this being said, I do think we can improve configuration in a few of ways. First, it would be nice to remove the arbitrary nature of "dev", "stage", and "prod". Instead, the user should be able to have any arbitrary environments with the exception of reserved ones like "default" and "global". Second, we should have _one_ set of overridable (#290) defaults. Third, we should be able to read configuration from _any_ file instead of one blessed Rocket.toml, and it should be possible to specify the path to that file programmatically or via an environment variable (#228). And fourth, it would be nice to be able to "merge" several configurations together. This would allow, for instance, to have a default.conf file with defaults as well as dev.conf and prod.conf that override any defaults set.
Is it that Rocket shouldn't default stage and prod environments to port 80?
Yes. That is the key issue here.
Port 80 is the canonical web server port.
I'd argue no.
If you're running the web server on a server with other _things_ normally you're probably using nginx/apache/etc. (which would be on port 80) to proxy.
If you're running the web server inside of a docker container (perhaps kubernetes / gke / swarm / etc.) then you _could_ use port 80 inside the container but that requires root and most advice on the web seems to say to keep the thing inside of the docker container running as not root if possible. As long as its not a protected port, the port doesn't actually matter that much on docker though as the port map config would be in the docker stack/compose/etc. configuration.
If you're running the web server directly in an embedded environment, you could and probably will use port 80 (or port 443).
I'd argue that the first two scenarios are far more widespread than the last.
8000 (even in _production_ mode)3000 (even in _production_ mode)500045678000I'm not seeing a large/popular web framework anywhere default their port to 80 (even when they have a concept of a production environment).
My point was that:
ROCKET_ENV is arbitrary and problematic. It encourages people to do weird stuff like if ROCKET_ENV == prod; do something; else do other thing -- The whole concept of fixed environments is totally flawed. NodeJS apps are the worst offenders here. 12Factor configuration via environment is the correct and easy way to configure an app@benwilber "It's impossible to run a Rocket app on port 80 unless it runs as root.". Err, not quite true. One can use capabilities in Linux to grant access to port 80 without requiring root. That said, it's not an unusual design to start as root and drop permissions. On Linux, there's quite a lot to do apart from just changing to an unprivileged user, so it's not a great design choice unless you're very clued up. Most of us aren't.
I agree with your problems with ROCKET_ENV. Personally, I find the ability to override configuration with environment variables as a potential security defect waiting to strike (although I've done it systems I've written, as it's been widely asked for), not least because it makes reproduciblity and isolation hard (and makes it harder still to capture configuration in audit-able source control). It's also hard to get things right when environment variables contains paths which can contain spaces... eg GCC CXX, cough
The most egregious examples recently have been CDPATH and the various bash function defects.
I'd rather we went with @mehcode's ideas. At the very least, let's take production-secrets out of the .toml configuration and let them reside someone that won't result in accidentally getting into source control. Whether that's 12 factor or not I don't care; I've been doing this sort of thing for years, as has Debian (eg run-parts).
As for the port, it should be the same in all environments unless overridden by explicit configuration. It's a lot less surprising.
Enough people seem to agree we shouldn't be defaulting to port 80, even for production. I'm fine with that. Let's make the change.
I can't really follow most of arguments here and think Sergios approach with port 80 is the right choice, because that is the officially defined port for a web server. And I think in contrast to Django, Rails etc. Rocket is indeed a web server and as such much more comparable to Apache, Nginx etc. You would not argue Apache should change its default port because you will probably run it behind a Varnish, would you?
@inta that depends on what you're deploying. Just about anything other than PHP you're probably deploying a different app server behind some kind of reverse proxy or load balancer. In that case I'd never run it on port 80 because it's unnecessary and I don't want it ever running privileged. The only reason to have something running on 80 is when it's specifically available to the open internet which typically isn't the case with most applications these days. There's almost always something in front of it.
I understood your argument, but I don't think it's valid. Should Apache change its default port? I think everything that talks HTTP should use port 80 as default, thats what it is defined for and I think that was done for reason.
I don't really care, because it's just one line in the config and it doesn't bother me changing it. In my opinion software developers should just stick with the standard and not go their own way if not necessary. By the way port 8000 is at least used by DMI and Shoutcast and maybe more, so that may conflict with other services on your network (though that port is not standardised).
@inta fundamentally Apache and Rocket solve very different problems. Do I think Apache should change it's default port? Honestly I don't really care what Apache does at this point. Like I said above, where Apache/nginx make sense is as edge nodes that function as load balancers, reverse proxies, serving static assets, and for hosting PHP because mod_php and fast_cgi are basically how PHP is deployed rather than an app server like Java, Ruby, Python, etc. use. There isn't really a reason to use Rocket to do any of those things because it's feature set doesn't lend itself to solving any of those problems.
When I build webapps now I don't worry about the edge because I don't run my own edge servers. While that's not necessarily true of everyone or even necessarily true of the majority it's the direction the trend has moved and a lot of new development is done. As more people move to the cloud, more and more people deploy their app servers behind a virtual load balancer that's part of the platform they deploy. They stick their static assets in something like an S3 bucket and front it with a CDN. For app servers the use of port 80 or even TCP doesn't matter because they're not being deployed publicly. In the case of many app servers TCP isn't even used in favor of unix domain sockets.
I'm not saying port 80 is dead or not used for HTTP anymore, far from it. Many apps these days are just not deployed on the edge and so tying them to port 80 by default doesn't make sense. Defaulting to something other than 80 removes the necessity of starting privileged, reduces friction to getting up and running, and is safer by reducing the possibility of some catastrophic flaw where privileges are not dropped correctly which the behavior and implementation of from platform to platform changes drastically.
Our company uses Rocket in production (on Centos) behind Nginx which does the redirection of www.domain.com to domain.com, SSL, http:// to https://, gzip compression, mirror-proxying the API for another web app at a different subdomain to avoid CORS issues etc.
So only Nginx needs to listen on port 80 but only to redirect to https.
And IIRC on IRC Sergio recommended running rocket behind a reverse proxy like Nginx in production anyway.
I know this is old, and maybe there is some more context that hasn't been included, but outside dynamic web frameworks that use third party web servers, I always found that port 80/443 for staging/production was common practice.
That aside, the only step I found to be missing from the documentation was one @raphaelcohn briefly touched on, by adding the bind socket file configuration to the binary itself, and allowing the binary to bind to the first 1024 ports.
sudo setcap CAP_NET_BIND_SERVICE=+eip rocket_binary
Of course at that point it's up to you to make the ownership and permissions changes to make it executable by a system-only user, and setup a rc script to help automatic the startup process. By that point, it is no different from any other universal web server in production. Maybe a more productive update could be documenting a Linux/UNIX production setup in the documentation to better inform those unaware of this process?
Most helpful comment
Yes. That is the key issue here.
I'd argue no.
If you're running the web server on a server with other _things_ normally you're probably using nginx/apache/etc. (which would be on port 80) to proxy.
If you're running the web server inside of a docker container (perhaps kubernetes / gke / swarm / etc.) then you _could_ use port 80 inside the container but that requires root and most advice on the web seems to say to keep the thing inside of the docker container running as not root if possible. As long as its not a protected port, the port doesn't actually matter that much on docker though as the port map config would be in the docker stack/compose/etc. configuration.
If you're running the web server directly in an embedded environment, you could and probably will use port 80 (or port 443).
I'd argue that the first two scenarios are far more widespread than the last.
8000(even in _production_ mode)3000(even in _production_ mode)500045678000I'm not seeing a large/popular web framework anywhere default their port to 80 (even when they have a concept of a production environment).