Sitemap

AWS EC2 NFS Server Setup: Step-by-Step Guide

7 min readSep 20, 2025

🌐 What is NFS?

Network File System (NFS) is a protocol developed by Sun Microsystems in 1984 that allows file sharing over a network. With NFS, you can access remote files as if they were local.

Key features of NFS:

  • Cross-platform compatibility β€” works across Linux, Unix, Windows
  • Transparency β€” remote files look like local files
  • Centralized storage β€” one location, multiple clients
  • Stateless protocol β€” the server does not track client states
Press enter or click to view image in full size
Press enter or click to view image in full size

When to choose Self-managed NFS:

  • Need custom NFS configurations
  • Cost optimization for large datasets
  • Specific performance tuning requirements
  • Integration with existing NFS infrastructure

When to choose EFS:

  • Need multi-AZ availability
  • Want fully managed solution
  • Variable workloads
  • Quick deployment requirement

πŸ“Œ Common Use Cases

  • Web servers β€” sharing static files
  • Kubernetes β€” used as Persistent Volumes (PVs)
  • Development environments β€” share source code and build artifacts
  • Log management β€” centralized log collection
  • Backups β€” automated backup and disaster recovery

πŸ—οΈ NFS Architecture on AWS EC2

Press enter or click to view image in full size

πŸ› οΈ Prerequisites

AWS CLI v2 installed

  • macOS: brew install awscli
  • Linux: download zip from AWS β†’ unzip β†’ install
  • AWS credentials configured
aws configure # Provide Access Key, Secret Key, Region, Output Format

Infrastructure Requirements:

  • 2x EC2 Instances (Amazon Linux 2023, t3.micro is fine for testing)
  • VPC + Subnet (default VPC is okay for labs)
  • Security Groups
  • SSH Key Pair for access

πŸ” Create SSH Key Pair (CLI)

aws ec2 create-key-pair \
--key-name nfs-lab-key \
--query 'KeyMaterial' \
--output text > nfs-lab-key.pem
chmod 400 nfs-lab-key.pem

πŸ”’ Security Group Rules

NFS Server SG

  • Port 2049 (TCP/UDP) β†’ Source: NFS Client SG
  • Port 111 (TCP/UDP) β†’ Source: NFS Client SG (rpcbind)
  • Port 22 (TCP) β†’ Source: Your IP

NFS Client SG

  • Port 22 (TCP) β†’ Source: Your IP

CLI Example (Server SG):

aws ec2 create-security-group \
--group-name nfs-server-sg \
--description "NFS Server SG"

aws ec2 authorize-security-group-ingress \
--group-name nfs-server-sg \
--protocol tcp --port 22 --cidr <YOUR_IP>/32

# NFS TCP and UDP (CORRECTED)
aws ec2 authorize-security-group-ingress \
--group-name nfs-server-sg \
--protocol tcp --port 2049 --source-group <CLIENT_SG_ID>

aws ec2 authorize-security-group-ingress \
--group-name nfs-server-sg \
--protocol udp --port 2049 --source-group <CLIENT_SG_ID>

# RPC TCP and UDP (CORRECTED)
aws ec2 authorize-security-group-ingress \
--group-name nfs-server-sg \
--protocol tcp --port 111 --source-group <CLIENT_SG_ID>

aws ec2 authorize-security-group-ingress \
--group-name nfs-server-sg \
--protocol udp --port 111 --source-group <CLIENT_SG_ID>

πŸ“‹ Step 1: Setup NFS Server

1.1 Launch EC2 (Server)

  • AMI: Amazon Linux 2023
  • Type: t3.micro
  • Subnet: Public subnet
  • SG: NFS Server SG

⚠️ Public Subnet Security Note: Since we’re using public subnet, ensure your security groups are properly configured to restrict access only to your client instances, not the entire internet.

CLI Option:

aws ec2 run-instances \
--image-id <AMI_ID> \
--count 1 \
--instance-type t3.micro \
--key-name nfs-lab-key \
--security-group-ids <SERVER_SG_ID> \
--subnet-id <SUBNET_ID> \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=NFS-Server}]'

1.2 Install Packages

sudo dnf update -y
sudo dnf install -y nfs-utils

1.3 Create Shared Directory

sudo mkdir -p /srv/nfs-share
echo "Hello NFS! Server time: $(date)" | sudo tee /srv/nfs-share/readme.txt
sudo chown -R nfsnobody:nfsnobody /srv/nfs-share
sudo chmod 755 /srv/nfs-share

1.4 Configure Exports

For Lab/Testing Environment:

echo "/srv/nfs-share *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports

For Production Environment (RECOMMENDED):

echo "/srv/nfs-share 10.0.0.0/8(rw,sync,no_subtree_check,root_squash)" | sudo tee -a /etc/exports
sudo exportfs -rav
sudo exportfs -v
Press enter or click to view image in full size

⚠️ Security Warning:

  • no_root_squash allows root access from clients - NEVER use in production
  • all_squash is recommended for maximum security
  • Always restrict by IP ranges, never use * in production
sudo exportfs -rav
sudo exportfs -v

1.5 Start Services

sudo systemctl enable --now nfs-server
sudo systemctl enable --now rpcbind
sudo systemctl status nfs-server
echo -e "[nfsd]\nthreads=16" | sudo tee -a /etc/nfs.conf
sudo systemctl restart nfs-server

1.6 Verify Server

sudo ss -tlnp | grep :2049
showmount -e localhost

πŸ“‹ Step 2: Setup NFS Client

2.1 Launch EC2 (Client)

  • Same AMI & type
  • Same VPC/subnet
  • SG: NFS Client SG

CLI Option:

aws ec2 run-instances \
--image-id <AMI_ID> \
--count 1 \
--instance-type t3.micro \
--key-name nfs-lab-key \
--security-group-ids <CLIENT_SG_ID> \
--subnet-id <SUBNET_ID> \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=NFS-Client}]'

2.2 Install Packages

sudo dnf update -y
sudo dnf install -y nfs-utils

2.3 Mount the Share

sudo mkdir -p /mnt/nfs-share

# Production mount with performance tuning
sudo mount -t nfs -o rsize=32768,wsize=32768,hard,timeo=600 \
<NFS_SERVER_PRIVATE_IP>:/srv/nfs-share /mnt/nfs-shares-share

# Verify mount
mount | grep nfs
df -h /mnt/nfs-share
Press enter or click to view image in full size

2.4 Persistent Mount

echo "<NFS_SERVER_PRIVATE_IP>:/srv/nfs-share /mnt/nfs-share nfs defaults,_netdev,nofail 0 0" | sudo tee -a /etc/fstab
sudo umount /mnt/nfs-share
sudo mount -a

πŸ”§ Performance Tuning

Server-Side Tuning

# Increase NFS server threads (AL2023/RHEL9+)
echo -e "[nfsd]\nthreads=16" | sudo tee -a /etc/nfs.conf
sudo systemctl restart nfs-server

Client-Side Tuning

# Add to /etc/fstab for optimal performance
rsize=32768,wsize=32768,hard,intr,timeo=600,retrans=2

Network Optimization

# On both server and client - increase network buffers
echo 'net.core.rmem_default = 262144' | sudo tee -a /etc/sysctl.conf
echo 'net.core.rmem_max = 16777216' | sudo tee -a /etc/sysctl.conf
echo 'net.core.wmem_default = 262144' | sudo tee -a /etc/sysctl.conf
echo 'net.core.wmem_max = 16777216' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

πŸ›‘οΈ Security Best Practices

1. Network Security

# For public subnet deployment, be extra careful with IP restrictions
# Option 1: Restrict to specific client IP
echo "/srv/nfs-share <CLIENT_PRIVATE_IP>/32(rw,sync,root_squash)" | sudo tee /etc/exports
# Option 2: Restrict to VPC range only
echo "/srv/nfs-share 10.0.0.0/16(rw,sync,root_squash)" | sudo tee /etc/exports
# NEVER use * wildcard in public subnets!
# ❌ DANGEROUS: "/srv/nfs-share *(rw,sync,root_squash)"

Public Subnet Additional Security:

# Block NFS access from internet using iptables
sudo iptables -A INPUT -s 10.0.0.0/16 -p tcp --dport 2049 -j ACCEPT
sudo iptables -A INPUT -s 10.0.0.0/16 -p udp --dport 2049 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 2049 -j DROP
sudo iptables -A INPUT -p udp --dport 2049 -j DROP
# Save iptables rules
sudo iptables-save | sudo tee /etc/sysconfig/iptables

2. Export Security

# Always use root_squash in production
root_squash # Maps root to anonymous user
all_squash # Maps all users to anonymous user (most secure)
no_root_squash # Preserves root access (⚠️ DANGEROUS)

3. File System Security

# Set proper ownership
sudo chown -R nfsnobody:nfsnobody /srv/nfs-share
# Set appropriate permissions
sudo chmod 755 /srv/nfs-share # Directory
sudo chmod 644 /srv/nfs-share/* # Files

βœ… Comprehensive Testing

Basic Functionality Tests

# Read test (Client)
cat /mnt/nfs-share/readme.txt
# Write test (Client)
echo "Test file from client $(hostname) at $(date)" | sudo tee /mnt/nfs-share/client-test.txt
# Verify on server
cat /srv/nfs-share/client-test.txt

Performance Testing

# Write performance test
dd if=/dev/zero of=/mnt/nfs-share/testfile bs=1M count=100
# Read performance test
dd if=/mnt/nfs-share/testfile of=/dev/null bs=1M
# Clean up test file
rm /mnt/nfs-share/testfile

Multi-Client Test

# Mount from multiple clients and test concurrent access
for i in {1..5}; do
echo "Client test $i from $(hostname)" | sudo tee /mnt/nfs-share/client-${i}.txt
done

🚨 Troubleshooting Guide

Common Issues and Solutions

1. Mount Fails with β€œConnection Refused”

# Check if NFS service is running
sudo systemctl status nfs-server
# Check if ports are open
sudo ss -tlnp | grep -E ":2049|:111"
# Check exports
sudo exportfs -v
# Test connectivity
telnet <nfs-server-ip> 2049

2. β€œPermission Denied” Errors

# Check export permissions
sudo exportfs -v
# Check file ownership
ls -la /srv/nfs-share/
# Check client access
showmount -e <nfs-server-ip>
# Debug with verbose mount
sudo mount -v -t nfs <server-ip>:/srv/nfs-share /mnt/test

3. β€œStale File Handle” Errors

# Unmount and remount
sudo umount /mnt/nfs-share
sudo mount -a
# If persistent, restart NFS services
sudo systemctl restart nfs-server # on server
sudo systemctl restart nfs-client.target # on client

4. Performance Issues

# Check network latency
ping <nfs-server-ip>
# Monitor NFS statistics
nfsstat -c # client stats
nfsstat -s # server stats
# Check mount options
mount | grep nfs
# Test with different buffer sizes
sudo mount -o remount,rsize=8192,wsize=8192 /mnt/nfs-share

5. Service Won’t Start

# Check system logs
sudo journalctl -u nfs-server -f
# Check configuration syntax
sudo exportfs -rav
# Check dependencies
sudo systemctl status rpcbind
sudo systemctl status nfs-server

Debug Commands Toolkit

# Server-side debugging
sudo exportfs -v # Show active exports
sudo rpcinfo -p # Show RPC services
sudo netstat -tlnp | grep nfs # Show NFS ports
sudo journalctl -u nfs-server # NFS logs
# Client-side debugging
showmount -e <server-ip> # Test server accessibility
sudo mount -v -t nfs <server>:<path> <mountpoint> # Verbose mount
rpcinfo -p <server-ip> # Test RPC connectivity
sudo tcpdump -i eth0 port 2049 # Network packet capture

🧹 Clean-Up and Cost Optimization

When finished testing:

  1. Terminate EC2 instances
  2. Delete security groups
  3. Remove SSH key pairs
  4. Delete unused EBS volumes
  5. Review CloudWatch logs retention

πŸ“š Additional Resources

⚠️ Important Notes:

  • Never use no_root_squash in production environments
  • Always use private subnets for NFS servers
  • Implement proper monitoring and alerting
  • Regular backup of NFS data is essential
  • Consider AWS EFS for managed NFS solution

--

--

No responses yet