grants/DEPLOYMENT_GUIDE_VPS.md
gdegelas a05331128b Atlas Green Morocco — grant strategy platform
- Full grant strategy framework for renewable energy & green hydrogen
- AI-powered grant studio, partner outreach, financial modeling
- Umami analytics with data-performance tracking
- Live Degelas metrics connected to solar.degelas.be
- Trilingual (EN/FR/AR) with i18n support
- Dockerized with Nginx frontend + Express API proxy
2026-06-01 09:44:03 +00:00

8.2 KiB

VPS Deployment Guide

Prerequisites

  • Ubuntu 22.04 LTS VPS (or similar)
  • Domain name pointing to your VPS IP
  • SSH access to the VPS
  • Docker & Docker Compose installed

Step 1: Server Setup

1.1 Update System

sudo apt update && sudo apt upgrade -y

1.2 Install Docker

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Log out and back in for group changes to take effect

1.3 Install Docker Compose

sudo apt install docker-compose-plugin -y

1.4 Configure Firewall (UFW)

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable

1.5 Install fail2ban (SSH protection)

sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Step 2: Clone Repository

cd /opt
sudo git clone <your-repo-url> atlasgreen
cd atlasgreen

Step 3: Configure Environment

# Copy example env file
cp .env.example .env

# Edit with your values
nano .env

Required Variables

# OpenAI API key (required for AI features)
OPENAI_API_KEY=sk-your-actual-key-here

# Degelas API (optional - mock data used if not set)
DEGELAS_API_URL=https://api.degelas.be
DEGELAS_API_KEY=dgl-your-key-here

# Production: set to your actual domain
CLIENT_ORIGIN=https://yourdomain.com

# Logging
LOG_LEVEL=info

Step 4: SSL Certificate (Let's Encrypt)

4.1 Install Certbot

sudo apt install certbot python3-certbot-nginx -y

4.2 Obtain Certificate

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

4.3 Auto-Renewal Test

sudo certbot renew --dry-run

4.4 Update nginx.conf for HTTPS

Create /etc/nginx/sites-available/atlasgreen:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    # SSL configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # Include the rest of your nginx.conf content here
    # (root, location blocks, etc.)
}

4.5 Enable Site

sudo ln -s /etc/nginx/sites-available/atlasgreen /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Step 5: Deploy with Docker Compose

5.1 Build and Start

cd /opt/atlasgreen
sudo docker compose up -d --build

5.2 Verify Deployment

# Check containers are running
sudo docker compose ps

# Check logs
sudo docker compose logs -f

# Test API health
curl http://localhost/api/health

Expected output:

{"status":"ok","timestamp":"2026-01-15T..."}

5.3 Test Website

Open https://yourdomain.com in your browser.


Step 6: Monitoring Setup

6.1 Log Rotation

Create /etc/logrotate.d/atlasgreen:

/var/log/nginx/atlasgreen/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

6.2 Uptime Monitoring

Sign up for free monitoring:

Configure to monitor https://yourdomain.com/api/health

6.3 Disk Space Alerts

# Add to crontab (crontab -e)
0 6 * * * if [ $(df / | tail -1 | awk '{print $5}' | sed 's/%//') -gt 80 ]; then echo "Disk space warning!" | mail -s "Disk Alert" your@email.com; fi

Step 7: Backup Strategy

7.1 Automated Backups

Create /opt/atlasgreen/backup.sh:

#!/bin/bash
set -e

BACKUP_DIR="/backups/atlasgreen"
DATE=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup .env (critical!)
cp .env $BACKUP_DIR/env_$DATE

# Backup docker volumes (if any)
# docker run --rm -v atlasgreen_data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/data_$DATE.tar.gz /data

# Backup docker-compose.yml
cp docker-compose.yml $BACKUP_DIR/compose_$DATE

# Keep only last 7 backups
find $BACKUP_DIR -type f -mtime +7 -delete

echo "Backup completed: $DATE"

Make executable:

chmod +x /opt/atlasgreen/backup.sh

7.2 Schedule Backups

# Add to crontab (crontab -e)
0 2 * * * /opt/atlasgreen/backup.sh >> /var/log/atlasgreen_backup.log 2>&1

7.3 Test Restore

Periodically test restoring from backup on a test server.


Step 8: Security Hardening

8.1 SSH Hardening

Edit /etc/ssh/sshd_config:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers your_username

Restart SSH:

sudo systemctl restart sshd

8.2 Automatic Security Updates

sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades

8.3 Docker Security Scan

# Install Trivy (vulnerability scanner)
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin

# Scan images
trivy image atlas-green-frontend:latest
trivy image atlas-green-api:latest

Troubleshooting

Container Won't Start

# Check logs
sudo docker compose logs api-server
sudo docker compose logs frontend

# Check if port is in use
sudo lsof -i :80
sudo lsof -i :3001

# Restart containers
sudo docker compose restart

API Returns 502 Bad Gateway

# Check if API server is running
sudo docker compose ps

# Check API logs
sudo docker compose logs api-server

# Check nginx config
sudo nginx -t

# Check nginx logs
sudo tail -f /var/log/nginx/error.log

SSL Certificate Issues

# Check cert status
sudo certbot certificates

# Renew if needed
sudo certbot renew

# Reload nginx
sudo systemctl reload nginx

Disk Space Full

# Check disk usage
df -h

# Clean up old Docker images
sudo docker image prune -a

# Clean up old containers
sudo docker container prune

# Check log sizes
sudo du -sh /var/log/*

Performance Tuning

Nginx Worker Processes

Edit /etc/nginx/nginx.conf:

worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
}

Docker Resource Limits

Edit docker-compose.yml:

services:
  api-server:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 128M
  
  frontend:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M

Maintenance Commands

Update Application

cd /opt/atlasgreen
git pull
sudo docker compose up -d --build

View Logs

# All services
sudo docker compose logs -f

# Specific service
sudo docker compose logs -f api-server

# Last 100 lines
sudo docker compose logs --tail=100

Restart Services

# All services
sudo docker compose restart

# Specific service
sudo docker compose restart api-server

Check Health

# API health
curl http://localhost/api/health

# Check containers
sudo docker compose ps

# Check disk space
df -h

# Check memory
free -h

Rollback Procedure

If deployment fails:

1. Stop New Deployment

sudo docker compose down

2. Revert Code

cd /opt/atlasgreen
git checkout <previous-commit>

3. Rebuild

sudo docker compose up -d --build

4. Verify

sudo docker compose logs -f
curl http://localhost/api/health

Contact & Support

Issue Action
Server down Check VPS provider console, reboot if needed
SSL expired Run sudo certbot renew
Disk full Clean logs, prune Docker, expand disk
API errors Check logs, restart API container
Database issues N/A (no database in this app)

Deployment Version: 1.0
Last Updated: January 2026