LinuxDevOpsNginxSecurityServer Administration
Linux Server Administration for Full-Stack Developers
Umut Korkmaz2025-01-0511 min read
As a full-stack developer who frequently deploys applications on Linux servers, I've compiled the essential knowledge every developer should have. This isn't meant to replace dedicated DevOps—it's about being self-sufficient when you need to be.
Initial Server Setup
When you first get a fresh Ubuntu/Debian server:
bash# Update packages
sudo apt update && sudo apt upgrade -y
# Create a non-root user
sudo adduser deploy
sudo usermod -aG sudo deploy
# Set up SSH key authentication
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# Add your public key to ~/.ssh/authorized_keys
# Disable password authentication
sudo nano /etc/ssh/sshd_config
# Set: PasswordAuthentication no
sudo systemctl restart sshd
Nginx as Reverse Proxy
For Node.js/Next.js applications, Nginx handles SSL and load balancing:
nginx# /etc/nginx/sites-available/myapp.conf upstream nodejs_app { server 127.0.0.1:3000; server 127.0.0.1:3001; keepalive 64; } server { listen 80; server_name example.com www.example.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name example.com www.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; ssl_prefer_server_ciphers off; # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # Gzip compression gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml application/json application/javascript application/xml; location / { proxy_pass http://nodejs_app; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_cache_bypass $http_upgrade; proxy_read_timeout 86400s; proxy_send_timeout 86400s; } # Static files with caching location /_next/static/ { alias /var/www/myapp/.next/static/; expires 1y; add_header Cache-Control "public, immutable"; } location /public/ { alias /var/www/myapp/public/; expires 30d; add_header Cache-Control "public"; } }
Process Management with PM2
Keep your Node.js apps running reliably:
bash# Install PM2 globally
npm install -g pm2
# Start application with cluster mode
pm2 start npm --name "myapp" -i max -- start
# Save process list for restart on reboot
pm2 save
pm2 startup
# Useful PM2 commands
pm2 logs myapp # View logs
pm2 monit # Real-time monitoring
pm2 reload myapp # Zero-downtime reload
PM2 ecosystem file for complex setups:
javascript// ecosystem.config.js
module.exports = {
apps: [{
name: 'myapp',
script: 'npm',
args: 'start',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3000
},
error_file: '/var/log/myapp/error.log',
out_file: '/var/log/myapp/out.log',
merge_logs: true,
max_memory_restart: '500M'
}]
};
Firewall Configuration with UFW
bash# Enable UFW
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (important - don't lock yourself out!)
sudo ufw allow ssh
# Allow HTTP and HTTPS
sudo ufw allow 'Nginx Full'
# Allow specific ports if needed
sudo ufw allow 27017/tcp # MongoDB (only if needed externally)
# Enable firewall
sudo ufw enable
# Check status
sudo ufw status verbose
SSL with Let's Encrypt
Free SSL certificates with automatic renewal:
bash# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Obtain certificate
sudo certbot --nginx -d example.com -d www.example.com
# Test automatic renewal
sudo certbot renew --dry-run
# Certificate auto-renews via systemd timer
sudo systemctl status certbot.timer
Log Management
bash# View application logs
tail -f /var/log/myapp/out.log
# Nginx access logs
tail -f /var/log/nginx/access.log
# System logs
journalctl -u nginx -f
# Log rotation (already configured but customize if needed)
sudo nano /etc/logrotate.d/myapp
Example logrotate configuration:
/var/log/myapp/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data www-data
sharedscripts
postrotate
pm2 reloadLogs
endscript
}
Monitoring and Alerts
Basic monitoring with shell scripts:
bash#!/bin/bash
# /opt/scripts/health-check.sh
APP_URL="https://example.com/api/health"
SLACK_WEBHOOK="your-webhook-url"
response=$(curl -s -o /dev/null -w "%{http_code}" $APP_URL)
if [ $response != "200" ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"⚠️ Health check failed: $APP_URL returned $response\"}" \
$SLACK_WEBHOOK
fi
Add to crontab:
bash# Check every 5 minutes
*/5 * * * * /opt/scripts/health-check.sh
Security Hardening Checklist
- Keep system updated:
sudo apt update && sudo apt upgrade - Disable root login via SSH
- Use SSH key authentication only
- Configure firewall (UFW)
- Install and configure Fail2ban
- Regular backups
- Monitor logs for suspicious activity
bash# Install and configure Fail2ban
sudo apt install fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
# Enable for SSH and Nginx
# [sshd]
# enabled = true
# [nginx-http-auth]
# enabled = true
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
These skills have proven invaluable across projects like Kapsül Mobilya and E-Export City, where I manage the full deployment pipeline from development to production.