Anik Sikder
Technical Writing/networking/how-can-an-app-reach-a-database-that-the-internet-cannot
article.sh

$ open article

networking

How Can an App Reach a Database That the Internet Cannot?

15 min readAugust 26, 2026
Public and Private Subnet Architecture with Application and Database Layers

Hey engineers! 👋

In the previous article, we answered a fundamental question:

How does one server find another server?

We explored DNS, Private DNS, and Service Discovery the mechanisms that turn something like:

code
postgres.internal.company

into a reachable destination inside a network.

But finding a server is only half of the story.

Knowing where a server is doesn't automatically mean you're allowed to connect to it.

That leads us to a more interesting question.

Most developers eventually learn this architecture:

code
User
  ↓
Application
  ↓
Database

But how does this actually work at the network level?

If the application can connect to PostgreSQL, why can't someone on the Internet connect to the same database?

This sounds like a simple networking question.

It isn't.

The answer involves:

  • Network routing
  • Public and private subnets
  • VPCs
  • Security groups
  • Firewall rules
  • Network isolation
  • Access boundaries
  • Defense in depth

And these concepts ultimately determine something much bigger:

Which systems are allowed to talk to which other systems?

That's one of the most important questions in production infrastructure.

Because there is a critical difference between:

code
Can I find the server?

and:

code
Can I reach the server?

And an even more important difference between:

code
Can I reach the server?

and:

code
Am I allowed to connect?

In the previous article, we focused on finding the destination.

In this article, we'll focus on controlling access to that destination.

Let's break it down.


The Architecture We Usually See

Imagine a typical SaaS application:

code
                    Internet
                        │
                        ▼
                 Load Balancer
                        │
                        ▼
                  Application
                        │
                        ▼
                   PostgreSQL

The application needs the database.

Customers don't.

That distinction is extremely important.

The customer needs:

code
Internet
   ↓
Application

The application needs:

code
Application
   ↓
Database

But there should usually be no direct path like this:

code
Internet
   ↓
Database

This is where cloud networking starts becoming interesting.


The First Principle: Not Everything Needs to Be Reachable

A common mistake in infrastructure design is thinking:

code
If a service needs to work,
it should be reachable.

Modern infrastructure follows almost the opposite principle:

code
Make only what needs to be reachable,
reachable.

For example:

code
Public
  │
  ├── Load Balancer
  │
  └── API Gateway

Private
  │
  ├── Application Servers
  ├── Background Workers
  ├── Redis
  └── PostgreSQL

The database doesn't need to accept connections from the public Internet.

So why expose it?

You don't.

This simple decision dramatically reduces the attack surface.


Public Subnet vs Private Subnet

Inside a cloud network such as a VPC, resources are commonly organized into different network boundaries.

Two of the most important concepts are:

code
Public Subnet
Private Subnet

Think about a building.

There might be:

code
Public Area
     ↓
Reception
Meeting Room
Waiting Area

And deeper inside:

code
Restricted Area
     ↓
Operations
Finance
Infrastructure
Records

Not everyone who can enter the building should be able to enter every room.

Cloud networks work with a similar principle.


What Is a Public Subnet?

A public subnet is a subnet whose routing configuration provides a path toward an Internet Gateway.

Resources placed there can be Internet-facing when their own network configuration also permits it for example, when they have a public IP or are exposed through a public load balancer.

Typical examples include:

code
Load Balancers
Reverse Proxies
Internet-facing Web Servers
Bastion Hosts

A simplified architecture might look like:

code
                 Internet
                     │
                     ▼
              Internet Gateway
                     │
                     ▼
               Public Subnet
                     │
                     ▼
              Load Balancer

This is where Internet-facing traffic enters the system.


What Is a Private Subnet?

A private subnet is designed for resources that should not be directly reachable from the public Internet.

Typical resources include:

code
Application Servers
PostgreSQL
MySQL
Redis
RabbitMQ
Kafka
Background Workers
Internal Services

A simplified architecture:

code
Internet
   ✖
   │
   ▼
Private Subnet
   │
   ├── Application
   ├── Redis
   └── PostgreSQL

The important idea is not:

"Nobody can access these machines."

It is:

"They are not directly reachable from the public Internet."

That distinction matters.


Private Does Not Mean Isolated

This is one of the most common misunderstandings.

Many developers hear:

code
Private Subnet

and think:

code
Nothing can connect to it.

Not true.

A private subnet can communicate with other resources inside the same VPC.

For example:

code
Application Server
10.0.1.10
       │
       ▼
PostgreSQL
10.0.2.20

Both resources may exist inside:

code
VPC
10.0.0.0/16

The traffic can remain inside the cloud network.

It doesn't need to travel across the public Internet.


So How Does the App Reach the Database?

Suppose:

code
Application Server
10.0.1.10

needs to connect to:

code
PostgreSQL
10.0.2.20:5432

The application creates a TCP connection:

code
10.0.1.10
      │
      │ TCP :5432
      ▼
10.0.2.20

The VPC routing system determines how packets should move between those network destinations.

If the route exists and the relevant security controls permit the traffic, the connection succeeds.

There is no requirement for the database to have a public IP.

In fact, keeping the database private is usually the safer design.


Then What Stops Everyone Else?

This is where Security Groups become important.

Routing answers:

Where should this packet go?

Security controls answer:

Is this traffic allowed?

These are different questions.


Security Groups: The Access Control Layer

In AWS, a Security Group acts as a stateful virtual firewall associated with resources such as EC2 instances and certain managed services.

Imagine a building.

The subnet is the area of the building.

The security group is the access control at the door.

The database exists.

The network path may exist.

But access can still be restricted.

For PostgreSQL, the standard port is:

code
5432

A dangerous rule might look like:

code
Inbound

Port: 5432
Source: 0.0.0.0/0

That effectively allows connection attempts from anywhere that can reach the database.

That is rarely what you want for a production database.


The Better Rule

Instead of:

code
Allow everyone

define:

code
Allow application servers

For example:

code
Database Security Group
        │
        └── Inbound
              │
              ├── Protocol: TCP
              ├── Port: 5432
              └── Source: App Security Group

Now the access relationship becomes:

code
Internet User
      ✖

Random Server
      ✖

Unrelated Service
      ✖

Application Server
      ✔

This is much more meaningful than simply allowing a large IP range.


Why Security Group References Matter

Consider an application running on multiple servers.

Initially:

code
10.0.1.10

So someone might configure:

code
Allow 10.0.1.10 → PostgreSQL:5432

Then autoscaling happens.

Now there are:

code
10.0.1.10
10.0.1.11
10.0.1.12
10.0.1.13

Tomorrow there may be twenty.

The infrastructure is dynamic.

Hardcoding individual IP addresses creates unnecessary operational complexity.

Instead, define an application security group:

code
app-sg

Attach it to application servers.

Then configure the database:

code
db-sg

Inbound:
5432
Source:
app-sg

Now the rule expresses the actual architectural relationship:

code
Application Layer
       │
       │ allowed
       ▼
Database Layer

The exact server IP becomes less important.


Network Access Is a Chain of Decisions

A database connection isn't simply:

code
Can I ping the database?

Multiple layers can influence whether traffic succeeds.

Conceptually:

code
Application
    │
    ▼
DNS Resolution
    │
    ▼
Route
    │
    ▼
Network ACL
    │
    ▼
Security Group
    │
    ▼
Database Listener
    │
    ▼
PostgreSQL

If any required layer is incorrectly configured, the connection can fail.

This is why production networking can feel confusing.

There isn't always one single "firewall."

There are multiple boundaries.


A Production-Style Architecture

A more realistic architecture might look like this:

code
                         Internet
                             │
                             ▼
                    ┌─────────────────┐
                    │  Load Balancer  │
                    │     Public      │
                    └────────┬────────┘
                             │
                             ▼
                    ┌─────────────────┐
                    │ Application     │
                    │    Servers      │
                    │    Private      │
                    └────────┬────────┘
                             │
                  ┌──────────┴──────────┐
                  │                     │
                  ▼                     ▼
          ┌──────────────┐      ┌──────────────┐
          │    Redis     │      │  PostgreSQL  │
          │   Private    │      │   Private    │
          └──────────────┘      └──────────────┘

Notice the boundaries.

The Internet can reach the load balancer.

The load balancer can reach the application.

The application can reach PostgreSQL.

But the Internet does not get a direct path to PostgreSQL.


This Is Defense in Depth

Now imagine the application itself contains a vulnerability.

An attacker manages to compromise a public-facing component.

A poorly designed network might look like:

code
Compromised Server
       │
       ├── Database ✔
       ├── Redis ✔
       ├── Internal APIs ✔
       └── Everything Else ✔

The blast radius becomes enormous.

A better architecture might look like:

code
Compromised Server
       │
       ├── Database ✔
       ├── Redis ✖
       ├── Internal Service ✖
       └── Other Systems ✖

The attacker may still have compromised one component.

But the compromise doesn't automatically become a compromise of the entire environment.

That is the value of segmentation.


Security Is About Blast Radius

One of the most useful ways to think about infrastructure security is:

What happens if one component is compromised?

Not:

Can anything ever be hacked?

That second question is unrealistic.

Production systems should be designed with the assumption that individual components can fail or become compromised.

The goal is to limit the damage.

For example:

code
Internet
   │
   ▼
Public Service
   │
   ▼
Private Application
   │
   ▼
Private Database

Each layer has a limited set of allowed relationships.

This creates smaller blast radiuses.


Why This Matters Beyond Security

Network isolation isn't only about preventing attackers.

It also improves operational control.

Suppose a database is publicly accessible.

Then many different systems can potentially attempt to connect:

code
Internet
   │
   ├── Bots
   ├── Scanners
   ├── Attackers
   ├── Unknown Services
   └── Legitimate Clients

Now the database must deal with traffic it never needed in the first place.

A private database changes the model:

code
Application Layer
       │
       ▼
Database

The allowed communication becomes explicit.

That improves:

  • Security
  • Reliability
  • Troubleshooting
  • Operational visibility
  • Compliance
  • Change management

The Business Impact Is Hidden in the Architecture

A network diagram may look purely technical.

But every boundary represents a business decision.

Consider a database containing:

code
Customer Accounts
Payment Records
Orders
Personal Information
Internal Business Data

If that database is accidentally exposed, the consequences can extend far beyond engineering:

code
Misconfiguration
      ↓
Unauthorized Access
      ↓
Data Exposure
      ↓
Incident Response
      ↓
Downtime / Investigation
      ↓
Customer Impact
      ↓
Financial & Reputation Cost

The infrastructure decision happened at the technical layer.

The consequences don't stay there.

This is why architecture is ultimately connected to business continuity.


"Nobody Knows the Database IP" Is Not Security

Another common assumption is:

code
Nobody knows my database IP.

Therefore:
I'm safe.

That's security through obscurity.

A better assumption is:

code
Assume the attacker knows the address.

Then ask:

code
Can they establish a connection?

If the answer is:

code
No route
+
No public exposure
+
Security group denies access

then knowing the address doesn't help much.

The important boundary is not secrecy.

It is reachability and authorization.


Public Exposure vs Private Access

Let's compare the two models.

Public Database

code
Internet
    │
    ▼
Public IP
    │
    ▼
PostgreSQL:5432

The database is directly exposed to Internet traffic.

Even if authentication is strong, the attack surface is unnecessarily large.


Private Database

code
Internet
    │
    ✖
    │
    ▼
Private Network
    │
    ▼
PostgreSQL:5432

And:

code
Application
    │
    ✔
    ▼
PostgreSQL:5432

The database only needs to serve the application.

So the network should reflect that requirement.


A Simple Mental Model

Think of your infrastructure as a building.

code
                 STREET
                   │
                   ▼
             Public Lobby
                   │
                   ▼
             Employee Area
                   │
                   ▼
                Vault

The public can enter the lobby.

Employees can enter restricted areas.

Only authorized systems can reach the vault.

Now translate that into cloud architecture:

code
                 Internet
                    │
                    ▼
              Public Subnet
                    │
                    ▼
          Private Application Layer
                    │
                    ▼
            Private Database Layer

And Security Groups define:

code
Who can move between the layers.

That's the mental model worth remembering.


The Bigger Engineering Principle

A strong production architecture doesn't ask:

How do we make everything communicate?

It asks:

What actually needs to communicate?

Then it creates the smallest set of allowed paths.

For example:

code
Load Balancer
      │
      ▼
Application
      │
      ├──────► PostgreSQL
      │
      └──────► Redis

But:

code
Internet ─────X────► PostgreSQL

Internet ─────X────► Redis

Redis ─────────X────► PostgreSQL

unless those connections are explicitly required.

This is the principle of least privilege applied to networking.


Frequently Asked Questions

What is a public subnet?

A public subnet is a subnet whose routing configuration provides a path toward an Internet Gateway. Resources in it can be made Internet-facing when their own configuration permits public connectivity.


What is a private subnet?

A private subnet is designed for resources that should not be directly reachable from the public Internet.

Common examples include:

  • Application servers
  • Databases
  • Redis
  • Message brokers
  • Background workers
  • Internal services

Can an application connect to a database in a private subnet?

Yes.

Private does not mean isolated.

If the appropriate network routes exist and security controls permit the connection, an application in one private subnet can communicate with a database in another private subnet.


Why shouldn't a database normally be publicly accessible?

A public database unnecessarily increases the attack surface.

Instead of:

code
Internet
   ↓
Database

a safer architecture is usually:

code
Internet
   ↓
Load Balancer
   ↓
Application
   ↓
Database

The database only needs to accept connections from systems that actually use it.


What is a Security Group?

A Security Group is a virtual, stateful network firewall used to control allowed traffic to and from supported cloud resources.

For example:

code
Database Security Group

Inbound:
TCP 5432
Source:
Application Security Group

This allows PostgreSQL traffic from the application layer while denying unrelated sources.


Why use a Security Group instead of an IP address?

Infrastructure is dynamic.

Application servers may be created, destroyed, replaced, or scaled automatically.

Instead of maintaining:

code
10.0.1.10
10.0.1.11
10.0.1.12

a security-group relationship can express:

code
Application Layer
        ↓
Database Layer

This better represents the intended architecture.


Does a private database need a public IP?

No.

A database can be reachable from private application servers using private networking without having a public IP address.


What happens if an attacker compromises an application server?

That depends on the network architecture.

If the application server has unrestricted access to the environment, the attacker may be able to move laterally.

With segmentation and least-privilege access, the attacker may encounter multiple boundaries:

code
Compromised Application
        │
        ├── Required Database ✔
        ├── Internal Service ✖
        ├── Other Database ✖
        └── Management Systems ✖

This limits the potential blast radius.


What is defense in depth?

Defense in depth means relying on multiple independent security layers rather than a single control.

For example:

code
Network Isolation
       ↓
Private Subnet
       ↓
Security Group
       ↓
Application Authentication
       ↓
Database Authentication

If one layer fails, other layers can still provide protection.


Is hiding the database IP enough to secure it?

No.

Security through obscurity is not a reliable security strategy.

A stronger model assumes the address or infrastructure details may eventually become known and asks:

code
Can an unauthorized system actually reach it?

What is the difference between routing and security groups?

They solve different problems.

Routing determines where traffic can go:

code
Where should the packet go?

Security controls determine whether the traffic is allowed:

code
Is this traffic permitted?

Both can be required for a successful connection.


What is least privilege in networking?

Least privilege means giving a system only the network access it actually needs.

For example:

code
Application
   │
   ├── PostgreSQL:5432 ✔
   ├── Redis:6379 ✔
   └── Everything else ✖

The goal is to minimize unnecessary communication paths.


Why is network segmentation important?

Segmentation limits how far an attacker, malfunctioning service, or misconfigured application can reach.

Without segmentation:

code
One Compromise
      ↓
Entire Environment

With segmentation:

code
One Compromise
      ↓
Limited Access
      ↓
Limited Blast Radius

Should application servers also be public?

Not necessarily.

A common architecture is:

code
Internet
   ↓
Public Load Balancer
   ↓
Private Application Servers
   ↓
Private Database

The application servers don't need to be directly exposed when the load balancer is responsible for receiving Internet traffic.


What should developers understand about cloud networking?

Developers working with production systems should understand at least:

  • IP addressing
  • CIDR ranges
  • VPCs
  • Subnets
  • Routing
  • Internet Gateways
  • NAT
  • Security Groups
  • Network ACLs
  • DNS
  • Private networking
  • Service discovery
  • Load balancing

You don't need to become a network engineer to build applications.

But you should understand how your application actually reaches the systems it depends on.


Key Takeaways

  • Public does not automatically mean insecure, and private does not automatically mean secure.
  • Public exposure should exist only where there is a real requirement.
  • Private networking reduces unnecessary Internet exposure.
  • Routing determines possible network paths.
  • Security Groups determine whether specific traffic is allowed.
  • Least privilege applies to networks just as it applies to application permissions.
  • Segmentation reduces blast radius.
  • Infrastructure security is fundamentally about controlling communication paths.
  • The strongest architecture is often the one with the fewest unnecessary paths.

About the Author

Anik Sikder is a Software Engineer specializing in Backend Systems, DevOps, Cloud Infrastructure, and Software Architecture.

He writes about Python, Django, FastAPI, JavaScript, System Design, distributed systems, cloud infrastructure, and scalable software engineering practices.

$ tags

cloudawsnetworkingvpcpublic-subnetprivate-subnetsecurity-groupsinfrastructuresystem-designdevopscybersecurity

$ ls related_articles

status: end_of_file

Related Blueprints

Continue exploring related architecture patterns.

Cloud & Distributed Systems

Building event-driven services, background processing pipelines, and production-ready operational workflows.

01Event-driven architecture
02Async task processing
03Redis & caching
04Background workers
05Observability & monitoring