AWS Builder Center
The Server Is Running. So Why Can’t Anyone Reach It?

The Server Is Running. So Why Can’t Anyone Reach It?

A Practical Guide to Troubleshooting Linux, Docker, and AWS Networking.

Curious Mind ☁️ | Exploring AWS, Cloud Infrastructure & DevOps
A server can be running, an application can be active, and a Docker container can show a "Running" status—yet the application remains inaccessible from a browser.
This is a common challenge when moving applications from a local machine to the cloud.
The reason is simple: a running application is not necessarily a reachable application.
Let's explore how to troubleshoot this problem systematically using Linux commands, Docker networking, and AWS infrastructure.
1. Understand the Complete Network Path
Imagine deploying a web application inside a Docker container on an Amazon EC2 instance. You open its public IP address in your browser, but the connection fails.
The request must travel through several layers:
Browser → Public IP → AWS network rules → EC2 instance → Host port → Docker port mapping → Application
A failure at any point can make the application unreachable. The goal is to identify where the connection breaks instead of randomly changing configurations.
2. Check Whether the Application Is Listening
Start by checking which ports are accepting connections:
sudo ss -lntp
You might see:
LISTEN 0 128 127.0.0.1:8000 0.0.0.0:*
Notice "127.0.0.1". This is the loopback address. An application listening only on this address generally cannot accept connections through the server's external network interface.
For example, a Django development server can be started with:
python manage.py runserver 0.0.0.0:8000
Binding to "0.0.0.0" allows the application to listen on all IPv4 interfaces. However, Django's development server is not suitable for production.
Key lesson: A process can be running perfectly while listening on the wrong interface.
3. Test the Application Locally
Before investigating AWS networking, test the application directly from the EC2 instance:
curl -v http://127.0.0.1:8000/
Common results include:
- Connection refused: Nothing is accepting the connection at that address and port, or a local rule is rejecting it.
- HTTP 200: The server returned a successful response.
- HTTP 404: The requested path was not found.
- HTTP 500: The application encountered an internal error.
A successful local request does not prove that external access works. It only confirms that the application responds through that local address.
If the request fails, inspect the application service and its logs:
sudo systemctl status your-service
sudo journalctl -u your-service -n 100 --no-pager
Replace "your-service" with the actual service name. These commands can reveal startup errors, missing dependencies, and configuration problems.
4. Verify Docker Port Mapping
When an application runs inside Docker, distinguish between the container port and the host port.
Suppose your application listens on port "8000" inside the container. You can publish it on host port "8080":
docker run -d --name web-app -p 8080:8000 your-image
The format is:
HOST_PORT:CONTAINER_PORT
Here, traffic arriving at host port "8080" is forwarded to container port "8000".
Check the container and its published ports:
docker ps
docker port web-app
docker logs --tail 100 web-app
If the mapping is missing or incorrect, the application may work inside the container without being accessible through the expected host port.
Also verify that the application inside the container listens on the correct interface. Binding only to "127.0.0.1" inside the container can prevent connections arriving through its network interface.
Official reference: https://docs.docker.com/engine/network/port-publishing/
5. Check the AWS Security Group
If the application responds locally and Docker is configured correctly, investigate the AWS network configuration.
An EC2 security group acts as a virtual firewall controlling traffic to and from the instance.
If your application is published on port "8080", the security group must allow the required inbound TCP traffic on that port.
In the AWS Console:
1. Open EC2 → Instances.
2. Select your instance and open the Security tab.
3. Select its associated security group.
4. Review the inbound rules.
5. Confirm that the protocol, port, and source match your requirements.
For standard web traffic, the usual ports are TCP "80" for HTTP and TCP "443" for HTTPS.
Remember that allowing port "80" does not automatically allow port "8080".
Security tip: Avoid exposing unnecessary ports publicly. Restrict SSH access to trusted sources or use an appropriate managed access method, such as AWS Systems Manager Session Manager.
Official reference: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/TroubleshootingInstancesConnecting.html
6. Verify the EC2 Network Path
Even a correctly configured security group cannot compensate for an invalid network path.
For direct public IPv4 access, check these components:
Public IP address: Confirm that the instance has a suitable public entry point.
Subnet route table: The subnet generally needs a route such as:
0.0.0.0/0 → Internet Gateway
The Internet Gateway must also be attached to the VPC.
Network ACLs: These subnet-level controls may block traffic. Unlike security groups, network ACLs are stateless, so the necessary inbound and outbound rules—including return traffic—must be allowed.
Host firewall: Linux firewall rules can also block connections. Depending on the system, inspect "nftables", "iptables", or "ufw".
Each component serves a different purpose. A correct security group does not guarantee that the subnet has an internet route, and a valid route does not guarantee that the host firewall will accept traffic.
Private instances should use an appropriate architecture, such as a load balancer, VPN, or managed access service, rather than being exposed unnecessarily.
7. Use Commands to Narrow Down the Problem
Keep these commands handy when troubleshooting:
Check listening ports:
sudo ss -lntp
Test the local application:
curl -v http://127.0.0.1:8000/
Inspect Docker containers and port mappings:
docker ps
docker port web-app
Check application logs:
docker logs --tail 100 web-app
Test the published host port:
curl -v http://127.0.0.1:8080/
Inspect network interfaces and routes:
ip addr
ip route
Replace the example ports with those used by your application.
If the local application works but the published host port fails, investigate Docker networking and host-level rules. If the host port works locally but external access fails, examine AWS networking and firewall configuration.
8. Follow a Systematic Troubleshooting Process
Use this sequence whenever an application becomes unreachable:
1. Application: Does the process start successfully? Check its status and logs.
2. Listening address: Is it listening on the expected port and interface?
3. Local response: Does a local HTTP request succeed?
4. Docker: Is the correct container port published to the correct host port?
5. Host networking: Can the EC2 instance reach the application through the published port?
6. AWS networking: Do the security group, network ACLs, routes, and public addressing permit the connection?
This inside-out approach isolates the failure and reduces unnecessary configuration changes.
9. Common Mistakes to Avoid
Assuming a running container means the application is healthy. Container status alone does not confirm that the application is responding correctly.
Opening every port to the internet. Identify the required port and allow only the necessary traffic.
Changing multiple settings at once. Modify one relevant setting, retest, and use the result to guide the next step.
Blaming AWS immediately. The cause may be an application crash, incorrect port mapping, or local firewall rule.
Ignoring error messages. A timeout, connection refusal, HTTP 404, and HTTP 500 point toward different categories of failure.
Conclusion: Troubleshoot From the Inside Out
When a server is running but its application is unreachable, randomly opening ports or restarting services is rarely the best first step.
Verify that the application is healthy and listening on the correct interface. Test it locally, check Docker port publishing, and then investigate host-level and AWS networking.
The central principle is:
Verify the application first, the port mapping second, and the network path third.
Instead of changing every setting, find the first layer where the expected connection fails, gather evidence, and fix that layer.
Question for the community: When troubleshooting an unreachable application, which layer do you check first—the application process, Docker networking, the host firewall, or the cloud network configuration?
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article