Platform
Linux Network Security Fundamentals for Cloud Operations
A Linux and networking foundation note that connects shell commands, permissions, processes, ports, firewalls, DNS, and cloud operations.
When operating a cloud service, the problem at first appears to have an abstract name. Resource names such as Load Balancer, Security Group, NSG, Ingress, DNS, Private Subnet, and Bastion are at the front, but if you follow the actual failure, it often comes down to Linux processes, ports, routing tables, DNS resolution, file permissions, and logs.
For example, the statement “API is not responding” is not yet a cause. You need to narrow down in order whether the application process is dead, the port is listening, curl is happening locally, or only blocked from the outside, whether the DNS is pointing to the correct IP, whether the routing path is correct, and whether the TLS certificate or proxy is the problem. This article is a record of basic Linux commands, TCP/IP, firewall, SSH, and log checking within the cloud operation flow.
Failure analysis starts with the process
The first thing to look at when a server is unresponsive is the status of processes and services. In systemd-based Linux, check the service status with systemctl and the service log with journalctl.
systemctl status nginx
systemctl status ssh
systemctl status my-api
journalctl -u nginx -n 100 --no-pager
journalctl -u my-api -f
journalctl -xeCheck the process list with ps, top, htop, and pstree.
ps aux | grep nginx
ps -ef | grep java
pstree -p
topThe important thing here is to distinguish between “the process exists” and “the service is normal.” The process may be alive but return 500 for each request due to a DB connection failure, or the readiness endpoint may fail but the process itself may not terminate. The same perspective is needed for containers and Kubernetes. Even if the Pod is Running, you need to separately check whether the application is ready to process requests.
Check port and socket
If the process is alive, the next step is the port. Check whether the server is actually listening on ports such as 80, 443, 8080, and 3000.
ss -tulnp
ss -antp
netstat -tulnp
lsof -i :8080If you do not see a LISTEN status in the ss -tulnp output, the application has not opened the corresponding port. In this case, before viewing the external request, check it locally first.
curl -I http://127.0.0.1:8080
curl -v http://localhost:8080/healthIf local curl succeeds but fails externally, you should look at the firewall, security group, load balancer, and DNS rather than the application itself. Conversely, if it fails locally, you should first look at the application log, environment variables, port settings, and process execution account.
The confirmation flow frequently used in operations is simple as follows.
process exists?
-> port listening?
-> local curl succeeds?
-> host firewall allows?
-> cloud firewall allows?
-> load balancer target healthy?
-> DNS points to correct endpoint?DNS and name resolution
Users access the domain, but the server communicates through IP and port. Therefore, DNS is a point often missed in failure analysis. First, check which IP the domain is resolved to.
dig api.example.com
nslookup api.example.com
cat /etc/hosts
`
```/etc/hosts` can force domain and IP mapping locally. This is useful for development or temporary testing, but if left on a production server it can become a source of failure that ignores actual DNS changes.
```bash
sudo nano /etc/hostsEven if DNS returns the correct IP, results may vary depending on the user's location due to cache, TTL, CDN, and load balancer conditions. When using DNS/CDN-based configurations such as CloudFront, Route 53, or Traffic Manager, look at DNS responses and actual HTTP responses separately.
curl -I https://api.example.com
curl -v --resolve api.example.com:443:203.0.113.10 https://api.example.com
`
```--resolve` forces a connection to a specific IP while maintaining the Host header and TLS SNI. This is useful for separately checking whether DNS or a specific server instance is the problem.
## View TCP/IP request flow
Web requests do not “go to the backend” all at once, but pass through multiple layers.
```mermaid
sequenceDiagram
participant Browser
participant DNS
participant LB as Load Balancer
participant App as Linux App Server
participant DB as Database
Browser->>DNS: resolve api.example.com
DNS-->>Browser: return IP
Browser->>LB: TCP handshake / TLS / HTTP request
LB->>App: proxy request
App->>DB: query
DB-->>App: result
App-->>LB: HTTP response
LB-->>Browser: responseRather than memorizing all seven layers of OSI, it was more important to distinguish “which layer failed” in operations. If DNS fails, nothing is left in the application log. If the TCP connection fails, you should look at ports, firewalls, and routing. If TLS fails, you should look at your certificate, SNI, and proxy settings. If it is HTTP 500, you should look at the application and dependent service logs.
The same goes for ports. There are conventions such as 80/443 for external web traffic, 22 for SSH, 5432 for PostgreSQL, and 6379 for Redis, but in operation, “how far that port should be open” should be viewed more strictly. Database ports should not be open to the Internet, and should only be accessible from the application subnet.
Routing and subnet sense
In TCP/IP, the IP address is divided into network and host parts. The subnet mask defines its boundaries.
IP address: 192.168.1.10
Subnet: 255.255.255.0
CIDR: /24
Network: 192.168.1.0
Hosts: 192.168.1.1 - 192.168.1.254
Broadcast: 192.168.1.255Dividing 192.168.1.0/24 by /26 creates 4 small networks.
192.168.1.0/26 hosts .1 - .62
192.168.1.64/26 hosts .65 - .126
192.168.1.128/26 hosts .129 - .190
192.168.1.192/26 hosts .193 - .254Cloud's VPC/VNet, Subnet, and Route Table express this concept as a resource. Dividing Public Subnet and Private Subnet, attaching NAT Gateway and Internet Gateway, and setting Security Group/NSG are ultimately tasks that define “which network can go where.”
Check the current IP and routing table on the server.
ip addr
ip link show up
ip route show
route -nCheck the route to your destination.
ping 8.8.8.8
traceroute api.example.comSince there are many environments where ICMP is blocked, ping failure does not mean service failure. Check the port connection separately with curl for an HTTP service or nc for a TCP connection.
nc -vz api.example.com 443
nc -vz 10.0.2.15 5432The forms frequently seen in operation are as follows.
public subnet
- load balancer
- NAT gateway
private application subnet
- application server
- container node
private data subnet
- database
- cacheIn this structure, there is no reason for users to access the database directly. The browser only accesses the load balancer, and the application communicates with the DB within a private network. Therefore, firewall rules should be narrowed to “allow only necessary directions and ports.”
When to look at packets
If the application log and port status don't provide an answer, you may need to look at the packets. tcpdump captures packets going to and from a specified interface.
sudo tcpdump -i eth0
sudo tcpdump -i eth0 port 80
sudo tcpdump -i eth0 host 10.0.2.15If the request does not reach the server, it is most likely a front-end network or firewall problem. If requests come in but no responses go out, look at the application, local firewall, routing, and response path. Although packet capture is more of a last resort, it is a powerful tool that reduces guesswork.
When it comes to SSH connections, boundaries come before convenience.
SSH is a basic tool for managing remote servers. First, check the installation and status.
sudo apt install openssh-server
systemctl status sshOn the operating server, back up the configuration file before modifying it immediately.
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_configDirect root login is prevented, and the default port can be changed if necessary.
Port 2222
PermitRootLogin no
PasswordAuthentication noAfter applying the settings, first test the connection in a new terminal. Before closing the existing session, make sure you are connected with the new settings.
sudo systemctl restart ssh
ssh user@server.example.com -p 2222SSH key-based access is more secure than password.
ssh-keygen
ssh-copy-id user@server.example.com
ssh user@server.example.com
scp ./app.log user@server.example.com:/tmp/app.logIf connection fails, check for permission issues.
chmod 755 ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keysIn the cloud, it is default not to open SSH ports to the entire Internet. You must have management paths such as Bastion, VPN, SSM Session Manager, and Azure Bastion, and restrict access sources in security groups or NSG.
Viewing UFW and cloud firewall together
In Ubuntu, basic firewall rules can be handled with UFW.
sudo ufw status
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2222/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status numberedRules added incorrectly can be deleted by number.
sudo ufw delete 3
sudo ufw resetIn a cloud environment, the firewall is not a single layer. Even if allowed by Security Group/NSG, communication will fail if UFW inside the server blocks it. Conversely, even if it is open in UFW, it cannot be accessed from outside if Security Group/NSG blocks it. When looking at disability, both layers must be examined together.
Internet
-> Cloud firewall: Security Group / NSG
-> Host firewall: UFW / iptables / nftables
-> Process listening portOnce you understand this structure, the phrase “opened a port” becomes more specific. You need to check where it was opened, to whom it was opened, what direction the traffic is coming from, and whether the actual process is listening to the port.
Network boundaries learned from WSL2 port forwarding
In WSL2, Linux operates within a separate virtual network. Running NGINX or SSH inside WSL does not mean that external devices can immediately access it. You need to check the WSL IP and set up portproxy and firewall rules in Windows.
ip addr show eth0Add port forwarding with Windows PowerShell administrator privileges.
netsh interface portproxy add v4tov4 `
listenport=80 `
listenaddress=0.0.0.0 `
connectport=80 `
connectaddress=172.29.205.121
New-NetFirewallRule `
-DisplayName "WSL 80 Port" `
-Direction Inbound `
-LocalPort 80 `
-Protocol TCP `
-Action AllowConfirmation and deletion are also required.
netsh interface portproxy show all
netsh interface portproxy delete v4tov4 listenport=80 listenaddress=0.0.0.0Although this exercise looks like a local development environment, it resembles a cloud network. The request passes only when the network on which the service is running, the address coming from outside, the intermediate forwarding rules, and the firewall permission rules are all correct.
Logs, file permissions, integrity
In Linux, logs are the default place to look for failures and security events.
cd /var/log
sudo less auth.log
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
last
lastlog
historyFile permissions and owners also often cause problems.
ls -lh
chmod 640 app.conf
chown app:app app.confFor sensitive files, you may want to consider integrity checking or encryption.
sha256sum release.tar.gz
gpg -c secrets.txt
gpg secrets.txt.gpgIn an operational environment, you need to be able to track who is connected, which files have been changed, and which services have been restarted. Failure analysis and auditing become difficult if logs are not left or the timing is incorrect. So server time synchronization, log retention, access rights, and distribution history become part of operational reliability even though they may seem like small settings technically.
User, package, and service management are the basics of VM operation.
If you operate a VM directly in the cloud, you cannot only see the network. You need to check who can access the server, what packages are installed, and even what services are started automatically. The responsibility of the OS layer, which was invisible in managed services, becomes the operator's responsibility again in VMs.
Users and groups are the basic units of authority. Running all tasks as root is faster, but it is difficult to reduce the extent of damage when a failure or infringement occurs. Separate the application execution account, deployment account, and administrator account, and give sudo permission only to necessary users.
whoami
id appuser
groups appuser
sudo useradd --system --create-home --shell /usr/sbin/nologin appuser
sudo usermod -aG docker deployer
sudo passwd -l appuserPackage management is tied to security patches and reproducibility. If you arbitrarily install packages on an operating VM, it is difficult to recreate the same environment later. At a minimum, it is better to leave an installation command and version, and code repeated configurations in a way such as cloud-init, Ansible, Packer, or Terraform provisioner.
sudo apt update
apt list --upgradable
dpkg -l | grep nginx
apt-cache policy docker.ioService management is based on systemctl. Check whether the process is alive, whether it starts automatically at boot, and whether there is a recent failure log.
systemctl status nginx --no-pager
systemctl is-enabled nginx
journalctl -u nginx --since "30 minutes ago" --no-pagerRegistering an application as a systemd service allows you to specify restart policy, execution account, and environment variable boundaries beyond simple background execution.
[Unit]
Description=Backend API
After=network.target
[Service]
User=appuser
Group=appuser
WorkingDirectory=/srv/backend
EnvironmentFile=/etc/backend/backend.env
ExecStart=/usr/bin/node /srv/backend/server.js
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
`
ExecStart` is not the only part of this file to look at. Operational settings include what account it runs under, where environment variables are injected, whether to restart in case of failure, and even whether to prevent privilege escalation. Even if you use containers and Kubernetes, this feeling does not disappear. Pod's securityContext, liveness probe, and restartPolicy ultimately express the same question in different layers.
Repeated inspection is left as a shell script
If you type the same command by hand every time, you will miss something. It is best to leave the basic inspection sequence as a shell script. The example below is a simple script that checks port, service status, DNS, and HTTP health check at once.
#!/usr/bin/env bash
set -euo pipefail
APP_SERVICE="${APP_SERVICE:-my-api}"
APP_PORT="${APP_PORT:-8080}"
APP_HOST="${APP_HOST:-api.example.com}"
echo "== service =="
systemctl is-active "$APP_SERVICE" || true
echo "== port =="
ss -tulnp | grep ":${APP_PORT}" || true
echo "== dns =="
dig +short "$APP_HOST" || true
echo "== local health =="
curl -fsS "http://127.0.0.1:${APP_PORT}/health" || true
echo "== external health =="
curl -fsS "https://${APP_HOST}/health" || trueGive execution permission and use it.
chmod +x check-api.sh
APP_SERVICE=my-api APP_PORT=8080 APP_HOST=api.example.com ./check-api.shEven with just this level of script, it becomes easy to share “how far we have checked” with team members during response to a failure. Later, you can develop methods such as GitHub Actions, cron, Azure Functions, AWS Lambda, and Prometheus exporter, but the starting point is to create a repeatable confirmation sequence.
Confirmation sequence in cloud operation
Assuming that you cannot access the API from the outside, you can view it in the following order.
1. DNS
dig api.example.com
2. Client-side HTTP
curl -v https://api.example.com/health
3. Load balancer / Ingress
target health, backend status
4. Cloud firewall
Security Group / NSG inbound rule
5. Host firewall
sudo ufw status
6. Process and port
systemctl status app
ss -tulnp
7. Local response
curl -v http://127.0.0.1:8080/health
8. Logs
journalctl -u app -n 100
tail -f application.logAfter going through this sequence, the phrase “the server is not working” becomes more concrete. You can isolate whether the DNS is wrong, the load balancer sees the target as unhealthy, a security group is blocking it, or the server is open but the application is giving a 500.
Cleanup
Linux and network fundamentals may seem old knowledge, but they remain a necessary foundation for cloud and Kubernetes operations. Being able to see processes, ports, DNS, routing, firewalls, and logs can help you narrow down what's really going on behind abstracted cloud resources.
Good operations don't come from memorizing every command. This comes from knowing which layer to check first when a failure occurs and connecting the verification results to the next decision. Linux commands are the tools that execute the verification sequence, and TCP/IP and subnet are the language for understanding cloud networks. With this basic knowledge, you can structurally view Docker, Kubernetes, Load Balancer, DNS, and TLS issues.
Unauthorized copying, redistribution, and automated scraping are not permitted. Please cite the original URL when referencing this article.