systemctl status says active, curl 3,008 on the server returns 200, and the browser spins. The client's error tells you which gate to open. With the firewall from Opening 80 and 443 with ufw enabled, this loop ran from a second host (a network namespace with its own interface, standing in for your laptop):
for p in 80 443 8086 8087; do
curl -sS -m 5 -o /dev/null -w "port $p: HTTP %{http_code}\n" http://192.0.2.1:$p/
doneport 80: HTTP 200 curl: (7) Failed to connect to 192.0.2.1 port 443 after 0 ms: Could not connect to server port 443: HTTP 000 curl: (28) Connection timed out after 5002 milliseconds port 8086: HTTP 000 curl: (28) Connection timed out after 5001 milliseconds port 8087: HTTP 000
A fast refusal (curl error 7) means the packet reached the kernel and nothing listened, so it answered with a TCP reset: 443 is open in the firewall, but Apache 129 's Listen 443 sits inside <IfModule ssl_module> and mod_ssl is not enabled yet (Let's Encrypt). A timeout (error 28) means something dropped the packet silently, a firewall here or in the cloud, and the kernel log names it: journalctl -k -g 'UFW 280 BLOCK' showed [UFW BLOCK] IN=ch0106-h ... DPT=8086 ... SYN. After ufw allow for 8086 and 8087, port 8086 returned HTTP 200 but 8087 was refused: it listens on 127.0.0.1, and no firewall rule changes that.
Check the gates in order and stop at the first failure:
Listening, on the right address? sudo ss -tlnp (Ports and Sockets).
Answering locally? curl -I http://127.0.0.1:PORT/.
Allowed by the host firewall? sudo ufw status or sudo firewall-cmd --list-all.
Allowed by the cloud security group, from your address (Cloud Security Groups)?
Does DNS point here? Compare dig +short from outside with the address on eth0.