If this is a publicly-facing server (that is, you already keep 443 open to the Internet), then there's really no more harm in keeping port 80 open all the time as well, and that's the recommended configuration.
If this is an "internal" server, where the general Internet shouldn't have access to it, then I'd second Osiris's recommendation and use DNS-01 authentication instead. Some DNS providers make this really easy, and others don't so you need to use something like acme-dns.
The other option, which I've heard some people do, is automate/script the opening and closing of the hole in the firewall. That is, configure their ACME client to run some command to connect to the firewall and make port 80 open to all upon doing a renewal, and run another command afterward to close the port again. A lot of ACME clients have "hooks" that allow for running these sorts of custom scripts. But again, this may be really complicated depending on your infrastructure.
The fundamental issue is that in order to prove that you actually own the domain name you're trying to get a certificate for, Let's Encrypt needs to confirm that you own it as seen from everywhere on the Internet. The Internet can show different people different things for a variety of reasons, but to really "own" a name you need to be able to prove you can respond to the challenge the same way from everywhere. (And Let's Encrypt does check from multiple places.) This means that somewhere, you need a port open to the world. Depending on the challenge type, this might be 53 for DNS-01, 80 for HTTP-01, or 443 for TLS-ALPN-01, but something needs to be open to the world. For some reason, IT departments tend to have the most trust in their DNS server software and are okay with opening 53 to the world even when they're not willing to open anything else, which is why DNS-based challenges are the way a lot of people with restrictive firewalls tend to go.