RHEL: Red Hat Enterprise Linux - a commercial Linux distribution commonly used in enterprise environments
Nginx: A web server that can serve static files, reverse proxy to backend applications, load balance, etc.
This guide documents what I've learned so far about hosting multiple web apps on a single server. I moved away from Heroku to have more control and better understand how web deployment actually works. This is a reference for myself and others looking to do the same and get up and running quickly. While these examples show static file serving, Nginx can also reverse proxy to any backend application (Node.js, Python, Ruby, Java, etc.) running on different ports (e.g., proxy_pass http://localhost:3000).
- Port 80 must be open
- Nginx installed and running
- SSH access to server
With Internet Access:
cd ~
git clone https://github.com/username/myapp.gitWithout Internet (VM/isolated server):
# On local machine
tar -czf myapp.tar.gz --exclude='.git*' *
# Transfer to server
scp myapp.tar.gz user@server:~/
# On server
mkdir ~/myapp
cd ~/myapp
tar -xzf ../myapp.tar.gz
rm ../myapp.tar.gz# Ensure directory is accessible
chmod 755 ~/myapp# Edit nginx config
sudo nano /etc/nginx/nginx.conf
# Add location block inside server { } block (around line 40-60)
# See template below for exact placement# Test configuration
sudo nginx -t
# Reload if test passes
sudo systemctl reload nginxuser nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /var/www/html;
include /etc/nginx/default.d/*.conf;
# 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 Referrer-Policy "strict-origin-when-cross-origin" always;
# Homepage
location = / {
root $HOME;
try_files /homepage.html =404;
}
# ========== ADD YOUR APPS HERE ==========
location /myapp {
alias $HOME/myapp;
try_files $uri $uri/ /myapp/index.html;
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
# ========== END APP SECTION ==========
# Health check
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}- Upload app to
~/newapp/ - Run permissions:
chmod 755 ~/newapp - Add to nginx (inside server block):
location /newapp { alias $HOME/newapp; try_files $uri $uri/ /newapp/index.html; location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 30d; add_header Cache-Control "public, immutable"; } }
- Reload:
sudo nginx -t && sudo systemctl reload nginx
The homepage at ~/homepage.html is a simple landing page to list all your apps. You can also access apps directly via their URLs (e.g., http://server/myapp).
<!DOCTYPE html>
<html>
<head>
<title>Web Applications</title>
<style>
body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }
.app-list { list-style: none; padding: 0; }
.app-list li { margin: 10px 0; }
.app-list a { display: block; padding: 15px; background: #f5f5f5; text-decoration: none; color: #333; border-radius: 5px; }
.app-list a:hover { background: #e0e0e0; }
</style>
</head>
<body>
<h1>Available Applications</h1>
<ul class="app-list">
<li><a href="/app1/">App 1 Description</a></li>
<li><a href="/app2/">App 2 Description</a></li>
<!-- Add more apps here -->
</ul>
</body>
</html>To use: Edit the list to include your apps, or skip the homepage entirely and access apps directly.
| Problem | Solution |
|---|---|
| 403 Forbidden | Run permission commands again, check ls -la ~/myapp/ |
| 404 Not Found | Verify nginx path matches directory name |
| App won't load | Check error log: sudo tail -f /var/log/nginx/error.log |