You can certainly do it with paths, but it's generally cleaner and easier to do subdomains. Some apps don't like paths without additional setup and/or reverse proxy configuration because they hard-code redirects to specific paths.
In some cases (if you are hosting services both internal and externally), you'll want to configure a split brain DNS (a local DNS server that resolves internal host to internal IPs and external DNS resolves to public IPs).
Yes there's some setup with that, but once you really get into it -- you'll start automating that :) I have a script that reads all of my Traefik http routers via the rest API and updates my unbound DNS server automagically.
+1 for Traefik. I got tired of all of nginx's quirks. It's really powerful and I'm sure the combinations of achievable results are infinite with nginx... so for some use cases it makes sense. But seriously... almost every container I'm likely to deploy follows a fairly simple model and traefik to just "works" with everything I've tried so far. I have ALL the traefik config in docker compose labels so every single configuration element I need to spin up a container a second time or on a new host is in ONE place.