A web server can be healthy on the instance and still be unreachable from your browser. Apache, the guest operating system, the EC2 security group, subnet routing, public addressing, DNS, and TLS are separate layers. This guide verifies them in that order so “connection timed out” does not turn into random package reinstalls.

Quick install for Amazon Linux 2023

Terminalbash
sudo dnf upgrade -y
sudo dnf install -y httpd
sudo systemctl enable --now httpd

Risk level: caution. Review the command before running it.

What these commands change

  • dnf upgrade -y applies available package updates without an interactive confirmation; review changes first in controlled production maintenance windows.

  • dnf install httpd installs Apache and resolved dependencies from enabled AL2023 repositories.

  • systemctl enable --now both starts the current service and creates boot-time enablement.

  • Package and service changes are confined to the EC2 guest, but upgrading can restart components or require a reboot; snapshot/AMI and rollback planning should match workload risk.

Prerequisites and network model

  • An EC2 instance running Amazon Linux 2023 with a supported architecture and current repositories.

  • A safe administrative path: AWS Systems Manager Session Manager, EC2 Instance Connect, or SSH restricted to your trusted public IP/CIDR. Never expose SSH to 0.0.0.0/0 or ::/0 for convenience.

  • Outbound access to configured package repositories, directly or through appropriate VPC endpoints/NAT/proxy design.

  • For direct public browsing: a public IPv4/Elastic IP or IPv6 address, subnet route to an internet gateway, and matching security controls. A private instance normally sits behind a load balancer or other ingress tier.

  • Inbound TCP 80 for HTTP testing and TCP 443 for production HTTPS at the component that terminates those protocols.

Choose the ingress topology before opening ports

  • Direct public instance: simpler for a lab, but the instance owns public addressing, TLS, ingress rules, and availability concerns. Avoid making this the default production pattern.

  • Private instance behind an ALB: the load balancer owns public listeners/certificates while the instance accepts only the application port from the ALB security group.

  • CloudFront or another edge in front: DNS, certificate, origin policy, caching, and header behavior add another verification layer.

  • Document where TLS terminates and whether traffic from that tier to Apache is HTTP or HTTPS; otherwise redirects, secure cookies, and client-address handling are easy to misconfigure.

How a browser request reaches Apache

ec2-apache-request-path.txttext
Browser / client
      │ DNS resolves hostname
Public IP or load balancer listener :80/:443
      │ route table + internet gateway / load balancer path
Security group + network ACL
      │ allowed TCP connection
EC2 network interface
      │ guest firewall / SELinux policy where configured
Apache httpd listener → virtual host → /var/www/html content

Verify inward from the internet and outward from Apache instead of changing all layers together.

Failure clues by layer

  • A timeout usually points to address, route, security-group, network-ACL, host-firewall, or listener reachability.

  • An immediate connection refusal usually means the address is reachable but nothing accepts that port, or a firewall actively rejects it.

  • An HTTP 403/404/500 proves the request reached an HTTP server; move to virtual-host, filesystem, application, and Apache log analysis.

  • A TLS certificate/name error occurs after network reachability and TLS negotiation begin; it is not fixed by opening more ports.

1. Confirm the operating system first

Terminalbash
cat /etc/os-release
printf 'Kernel: '; uname -r
printf 'Architecture: '; uname -m

Why identification comes before installation

  • AL2023 reports an Amazon Linux 2023 identity and uses dnf; AL2 reports Amazon Linux 2 and historically uses yum.

  • Package names, repository versions, defaults, and lifecycle differ across Amazon Linux, Ubuntu, RHEL, and other AMIs.

  • The kernel/architecture record helps correlate repository, AMI, module, and vendor-support issues.

  • Capture the AMI ID and build provenance in infrastructure code or inventory; /etc/os-release alone cannot prove how the instance was launched.

2. Update and install only Apache

The old tutorial installed an entire LAMP stack and pinned PHP 7.2/MariaDB 10.2 Extras even when the goal was simply Apache. Those versions are obsolete. Start with httpd; add a current PHP runtime, database client/server, or application dependencies only when the workload actually requires them.

Terminalbash
sudo dnf check-update || test $? -eq 100
sudo dnf upgrade -y
sudo dnf install -y httpd

Risk level: caution. Review the command before running it.

Package-management takeaways

  • dnf check-update returns status 100 when updates are available; the conditional accepts that documented nonzero result without hiding other failures.

  • upgrade changes installed packages, so use an AMI/snapshot, autoscaling replacement, or tested rollback strategy for production.

  • Installing httpd does not automatically expose a network port through EC2 security groups.

  • Do not run package managers concurrently through user data, SSM, configuration management, and an interactive shell; lock contention and partial orchestration are avoidable.

3. Validate configuration and start httpd

Terminalbash
sudo httpd -t
sudo systemctl enable --now httpd
sudo systemctl status httpd --no-pager
sudo ss -ltnp | grep -E "(:80|:443)\b"

What healthy output means

  • httpd -t parses configuration and should report syntax success before a restart; it cannot validate every upstream application dependency.

  • enable --now persists startup and starts immediately; inspect the service result rather than assuming success from an empty shell response.

  • systemctl status shows recent state and log context. Full diagnostics may require journalctl -u httpd.

  • ss confirms a local listening socket. Port 443 appears only after an HTTPS listener is configured.

  • A listener on 0.0.0.0:80 or [::]:80 is local evidence; it does not prove that the VPC path permits public traffic.

4. Publish a minimal static page safely

site/index.htmlhtml
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>EC2 Apache check</title>
</head>
<body>
  <h1>Apache is serving this EC2 instance</h1>
  <p>Replace this test page during deployment.</p>
</body>
</html>

A harmless page for distinguishing your server from a default test response.

What this page verifies

  • The doctype and viewport provide predictable modern rendering; there is no application runtime or database dependency.

  • A unique heading distinguishes deployed content from a cached response, load balancer default, or Apache distribution test page.

  • Do not publish phpinfo() or similar environment dumps: they expose versions, modules, paths, variables, and configuration details.

  • Keep source content in version control and deploy it reproducibly rather than editing production files as root.

project-directorybash
sudo install -o root -g apache -m 0644 site/index.html /var/www/html/index.html
sudo restorecon -v /var/www/html/index.html 2>/dev/null || true
sudo httpd -t
sudo systemctl reload httpd

Risk level: caution. Review the command before running it.

Permissions and reload behavior

  • install copies one reviewed file with explicit owner, group, and mode; Apache only needs read access for static content.

  • Avoid recursively making /var/www group-writable or owned by the interactive user on production servers. Use a deployment identity and least privilege.

  • restorecon restores the configured SELinux label when SELinux tooling/policy is present; the fallback prevents an absent command from blocking this portable step. Investigate real label failures instead of disabling SELinux.

  • A graceful reload applies configuration without the abrupt connection impact of a stop/start, but only after syntax validation.

5. Configure the EC2 security group

Attach an inbound rule for TCP 80 to the instance security group for public HTTP testing, or to the load balancer security group when Apache is private behind an ALB. Public websites commonly allow 0.0.0.0/0 and, when IPv6 is configured, ::/0 on ports 80/443. Administrative ports should remain restricted.

  • Direct instance: instance security group accepts client CIDRs on 80/443; the subnet and public address must support internet routing.

  • Behind an Application Load Balancer: load balancer group accepts clients; instance group accepts the application port only from the load balancer security group.

  • Network ACL: stateless rules must permit the request and return traffic; default NACLs typically do, custom NACLs may not.

  • IPv6: an IPv6 DNS record requires IPv6 addressing, route, and ::/0 security rule; an IPv4-only rule does not cover it.

  • Security-group changes apply to every associated resource. Review association scope before widening a rule.

6. Verify from inside and outside

Terminalbash
curl -fsS http://127.0.0.1/
curl -I http://127.0.0.1/
# From a separate client, replace the placeholder:
curl -I http://PUBLIC_DNS_NAME/

Interpret the two vantage points

  • Loopback success proves Apache and local content routing work; it bypasses EC2 ingress, public DNS, and internet routing.

  • -f treats HTTP 4xx/5xx as failure, -sS keeps successful output quiet while showing errors, and -I requests response headers.

  • PUBLIC_DNS_NAME is a placeholder. Test from outside the VPC path you intend users to take.

  • A public IP can change after stop/start unless you use an Elastic IP, load balancer, or stable DNS design.

  • Do not confuse an HTTP redirect with HTTPS readiness; follow and validate the certificate, hostname, and final response separately.

Amazon Linux 2 compatibility path

For an existing AL2 instance that cannot be migrated immediately, Apache itself is installed with yum. Do not revive the original amazon-linux-extras ... php7.2 line: it pins obsolete application components and is unnecessary for a static Apache server. Establish an AL2023 migration deadline and isolate the legacy workload.

Terminalbash
sudo yum update -y
sudo yum install -y httpd
sudo httpd -t
sudo systemctl enable --now httpd

Risk level: caution. Review the command before running it.

Legacy-host takeaways

  • These commands are for an already-existing AL2 system; they do not restore vendor support after end of life.

  • yum on AL2 and dnf on AL2023 reflect different platform generations; do not mix Extras-era recipes into AL2023.

  • Patch the instance as far as its repositories permit, reduce exposure, monitor it, back it up, and prioritize replacement over indefinite in-place accumulation.

  • Test application, PHP/runtime, database, SELinux, systemd, and package changes during migration; AL2023 is not an in-place major-version upgrade.

Troubleshooting ladder

  • Package not found: confirm OS/release, repository access, DNS/outbound path, time, and package-manager locks.

  • httpd fails to start: run httpd -t, then inspect systemctl status httpd and journalctl -u httpd; look for syntax, port collision, missing files, and permission/label errors.

  • Loopback works, public request times out: inspect public addressing/load balancer, route table, internet gateway, security groups, NACL, guest firewall, and correct DNS record.

  • 403 Forbidden: inspect directory/file execute/read permissions, Require directives, virtual-host/document root, and SELinux audit evidence.

  • 404 Not Found: confirm the active virtual host and document root; the file may exist under a directory Apache is not serving.

  • 503 through load balancer: inspect target-group port/protocol, health-check path, target health, instance group source, and application response.

  • Page shows old content: identify CDN/proxy/browser cache, DNS target, load-balancer target, and response headers before restarting Apache.

Production hardening checklist

  1. Run AL2023 on a repeatable AMI or launch template and automate patching/replacement.

  2. Keep instances private behind a load balancer where architecture permits; restrict SSH or replace it with Session Manager.

  3. Use HTTPS with managed certificate renewal and redirect HTTP; validate headers, protocol policy, and application cookies.

  4. Deploy immutable/versioned content with a non-interactive identity; keep /var/www non-writable by the web process unless explicitly required.

  5. Remove default/test/debug pages, directory listings, unused modules, sample apps, and exposed status endpoints.

  6. Send access/error/system logs and metrics to durable monitoring; alert on health, latency, 5xx, disk, certificate, and resource pressure.

  7. Back up application data/configuration, test restore and replacement, and avoid storing critical state only on an instance root volume.

Primary references