0% found this document useful (0 votes)
8 views12 pages

Production Server Guide

This document provides a comprehensive guide for setting up a production home server using Docker, Nginx, and ngrok, allowing for scalable multi-project management. It details the architecture, folder structure, installation steps, configuration files, and security measures necessary for a successful deployment. The guide also includes troubleshooting tips and instructions for auto-starting the server on boot.

Uploaded by

mirshadkvx
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views12 pages

Production Server Guide

This document provides a comprehensive guide for setting up a production home server using Docker, Nginx, and ngrok, allowing for scalable multi-project management. It details the architecture, folder structure, installation steps, configuration files, and security measures necessary for a successful deployment. The guide also includes troubleshooting tips and instructions for auto-starting the server on boot.

Uploaded by

mirshadkvx
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

🐳 Production Home Server

Docker + Nginx + ngrok Architecture Guide


Transforming your laptop into a scalable multi-project server

🌐 Your Public URL: [Link]

🏗 Architecture Overview

Your new production setup routes all public traffic through a single ngrok tunnel → Nginx →
Docker containers. Each project runs in its own isolated container, accessible via URL sub-
paths.

How Traffic Flows


Internet
|

ngrok (public HTTPS tunnel)
|

Nginx (port 80 — reverse proxy + router)
|
├── /api/ ──▶ fastapi-app container (port 8000)
├── /django/ ──▶ django-app container (port 8001)
├── /project3/ ──▶ project3-app container (port 8002)
└── / ──▶ dashboard container (port 3000)

💡 Key Benefit: Each project is completely isolated. You can start, stop, rebuild, or update one
project without touching any other.

📁 Folder Structure

Create this exact folder structure on your server. All projects live under /srv/projects.
/srv/projects/
├── [Link] # Master file — runs everything
├── nginx/
│ ├── [Link] # Main Nginx config
│ └── conf.d/
│ ├── [Link] # FastAPI routing rules
│ ├── [Link] # Django routing rules
│ └── [Link] # Dashboard routing rules
├── fastapi-app/
│ ├── Dockerfile
│ ├── [Link]
│ └── [Link]
├── django-app/
│ ├── Dockerfile
│ ├── [Link]
│ ├── [Link]
│ └── myproject/
│ ├── [Link]
│ ├── [Link]
│ └── [Link]
├── dashboard/ # Optional landing page
│ ├── Dockerfile
│ └── [Link]
└── shared/
└── .env # Shared environment variables

Create the structure with this single command:


mkdir -p /srv/projects/{nginx/conf.d,fastapi-app,django-app,dashboard,shared}

🐳 Step 1 — Install Docker & Docker Compose

Install Docker Engine


# Remove old versions
sudo apt remove docker docker-engine [Link] containerd runc -y

# Install dependencies
sudo apt update
sudo apt install ca-certificates curl gnupg lsb-release -y

# Add Docker's official GPG key


sudo mkdir -p /etc/apt/keyrings
curl -fsSL [Link] | sudo gpg --dearmor -o
/etc/apt/keyrings/[Link]

# Add Docker repository


echo "deb [arch=$(dpkg --print-architecture)
signed-by=/etc/apt/keyrings/[Link]] \
[Link] $(lsb_release -cs) stable" | \
sudo tee /etc/apt/[Link].d/[Link] > /dev/null
# Install Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli [Link] docker-compose-plugin -y

# Allow mirshad to run Docker without sudo


sudo usermod -aG docker mirshad
newgrp docker

# Verify
docker --version
docker compose version

📋 Step 2 — Master [Link]

This single file defines your entire infrastructure. Save it at /srv/projects/[Link]

# /srv/projects/[Link]
version: '3.9'

networks:
server-net: # All containers talk on this private network
driver: bridge

services:

# ── Nginx Reverse Proxy ────────────────────────────────────────


nginx:
image: nginx:alpine
container_name: nginx-proxy
ports:
- '80:80' # Only Nginx is exposed to host
volumes:
- ./nginx/[Link]:/etc/nginx/[Link]:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
networks:
- server-net
restart: always
depends_on:
- fastapi-app
- django-app
- dashboard

# ── FastAPI Project ─────────────────────────────────────────────


fastapi-app:
build: ./fastapi-app
container_name: fastapi-app
expose:
- '8000' # Only visible inside server-net, not the host
env_file:
- ./shared/.env
networks:
- server-net
restart: always
volumes:
- ./fastapi-app:/app # Live reload during dev

# ── Django Project ──────────────────────────────────────────────


django-app:
build: ./django-app
container_name: django-app
expose:
- '8001'
env_file:
- ./shared/.env
networks:
- server-net
restart: always
volumes:
- ./django-app:/app

# ── Optional Dashboard ──────────────────────────────────────────


dashboard:
build: ./dashboard
container_name: dashboard
expose:
- '3000'
networks:
- server-net
restart: always

# ── PostgreSQL Database ─────────────────────────────────────────


postgres:
image: postgres:15-alpine
container_name: postgres-db
expose:
- '5432'
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: strongpassword123
POSTGRES_DB: maindb
volumes:
- postgres_data:/var/lib/postgresql/data # Data persists on disk
networks:
- server-net
restart: always

volumes:
postgres_data: # Named volume — survives container restarts

⚙ Step 3 — Nginx Configuration


Main Nginx Config /srv/projects/nginx/[Link]
# /srv/projects/nginx/[Link]
worker_processes auto;

events {
worker_connections 1024;
}

http {
include /etc/nginx/[Link];
default_type application/octet-stream;

# Security headers
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;

# Logging
access_log /var/log/nginx/[Link];
error_log /var/log/nginx/[Link];

# Load all project configs


include /etc/nginx/conf.d/*.conf;
}

FastAPI Routing /srv/projects/nginx/conf.d/[Link]


# /srv/projects/nginx/conf.d/[Link]
server {
listen 80;
server_name _;

# FastAPI project at /api/


location /api/ {
proxy_pass [Link]
proxy_http_version 1.1;
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;
}

# Django project at /django/


location /django/ {
proxy_pass [Link]
proxy_http_version 1.1;
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;
}

# Dashboard at root /
location / {
proxy_pass [Link]
proxy_http_version 1.1;
proxy_set_header Host $host;
}
}

📦 Step 4 — Project Dockerfiles

FastAPI /srv/projects/fastapi-app/Dockerfile
FROM python:3.12-slim

WORKDIR /app

COPY [Link] .
RUN pip install --no-cache-dir -r [Link]

COPY . .

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "[Link]", "--port", "8000", "--reload"]

FastAPI /srv/projects/fastapi-app/[Link]
fastapi
uvicorn[standard]
psycopg2-binary
python-dotenv

Django /srv/projects/django-app/Dockerfile
FROM python:3.12-slim

WORKDIR /app

RUN apt-get update && apt-get install -y libpq-dev gcc && rm -rf
/var/lib/apt/lists/*

COPY [Link] .
RUN pip install --no-cache-dir -r [Link]

COPY . .

EXPOSE 8001

CMD ["python", "[Link]", "runserver", "[Link]:8001"]


Django /srv/projects/django-app/[Link]
django>=4.2
psycopg2-binary
gunicorn
python-dotenv
djangorestframework

🔒 Production Note: For real production use, replace runserver with gunicorn: gunicorn
[Link]:application --bind [Link]:8001 --workers 2

🔑 Step 5 — Shared Environment Variables

Save secrets in one place. All containers share this file.

/srv/projects/shared/.env
# Database
DB_HOST=postgres
DB_PORT=5432
DB_NAME=maindb
DB_USER=admin
DB_PASSWORD=strongpassword123

# Django
DJANGO_SECRET_KEY=your-very-secret-key-here
DJANGO_DEBUG=False
DJANGO_ALLOWED_HOSTS=[Link],localhost

# Public URL
PUBLIC_URL=[Link]

⚠️Security: Never commit the .env file to Git. Add it to .gitignore immediately.

🌐 Step 6 — Update ngrok Systemd Service

Your existing ngrok setup works fine. Just make sure it still points to port 80 (Nginx), which it
already does. No changes needed — ngrok tunnels to Nginx, which now routes to Docker
containers.

✅ Existing ngrok config is correct: addr: 80 — This points to Nginx, which distributes to all Docker
containers.
🚀 Step 7 — Launch Everything

First-time Launch
cd /srv/projects

# Build all images and start in background


docker compose up -d --build

# Watch logs
docker compose logs -f

Verify Everything is Running


# See all running containers
docker compose ps

# Test FastAPI internally


curl [Link]

# Test Django internally


curl [Link]

# Test via public URL


curl [Link]

⚡ Daily Operations Cheatsheet

Command What it does


docker compose ps Show all containers + status
docker compose logs -f Stream all container logs
docker compose logs fastapi-app -f Stream one project's logs
docker compose up -d --build fastapi-app Rebuild & restart one project only
docker compose restart nginx Reload Nginx config
docker compose stop django-app Stop one project
docker compose start django-app Start one project
docker compose down Stop all containers
docker compose down -v Stop all + delete volumes
docker exec -it fastapi-app bash Shell into a container
docker stats Live CPU/RAM usage
docker system prune -f Clean up unused images/containers

➕ Adding a New Project (Template)

Follow these 4 steps every time you add a new backend project:

Step A — Create project folder + Dockerfile


mkdir -p /srv/projects/my-new-project
# Add your code and Dockerfile (copy from fastapi-app template)

Step B — Add to [Link]


my-new-project:
build: ./my-new-project
container_name: my-new-project
expose:
- '8002'
env_file:
- ./shared/.env
networks:
- server-net
restart: always

Step C — Add Nginx routing rule


# In /srv/projects/nginx/conf.d/[Link]
# Add inside the server {} block:

location /newproject/ {
proxy_pass [Link]
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}

Step D — Deploy
cd /srv/projects
docker compose up -d --build my-new-project
docker compose restart nginx

# Your new project is live at:


# [Link]
🔒 Security Hardening

These steps protect your laptop server from unwanted access.

Firewall — Allow Only What's Needed


sudo ufw enable
sudo ufw allow ssh # SSH remote management
sudo ufw allow 80 # Nginx (ngrok connects here)
sudo ufw deny 5432 # Block direct Postgres access from outside
sudo ufw deny 8000 # Block direct FastAPI access from outside
sudo ufw deny 8001 # Block direct Django access from outside
sudo ufw status

Keep System + Docker Updated


sudo apt update && sudo apt upgrade -y
docker compose pull # Pull latest base images
docker compose up -d --build # Rebuild with latest images

Monitor Resource Usage


# Real-time container stats
docker stats

# Disk usage
docker system df

# Cleanup old images


docker image prune -f

🔧 Troubleshooting

Problem Fix
502 Bad Gateway Container crashed. Run: docker compose logs
<name> -f

Container keeps restarting Check logs: docker compose logs <name> --


tail=50

Nginx config error docker compose exec nginx nginx -t

Port conflict on host Check: sudo lsof -i :80 — stop conflicting


service
Database connection refused Make sure container name matches DB_HOST
in .env

Changes not taking effect Rebuild: docker compose up -d --build <name>

Disk full Run: docker system prune -f && docker volume


prune -f

🔄 Auto-Start on Laptop Boot

Create a systemd service so Docker Compose starts automatically when your laptop turns on.

Create the Service File


sudo nano /etc/systemd/system/[Link]

[Unit]
Description=Docker Compose Projects
After=[Link] [Link]
Requires=[Link]

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/srv/projects
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
User=mirshad

[Install]
WantedBy=[Link]

Enable It
sudo systemctl daemon-reload
sudo systemctl enable [Link]
sudo systemctl start [Link]

✅ Your Complete Stack Summary

Component Role
ngrok Public HTTPS tunnel
Nginx (Docker) Reverse proxy + router
FastAPI (Docker) Your FastAPI backends
Django (Docker) Your Django backends
PostgreSQL (Docker) Shared database
systemd services Auto-restart on boot

🎉 Your server is production-ready! Every project is isolated in Docker, Nginx routes traffic cleanly,
ngrok gives you a permanent public URL, and everything restarts automatically on reboot.

You might also like