Skip to main content

Overview

This guide covers everything needed to deploy the MaqAgr API to production, from environment configuration to database setup and containerization.

Environment Variables

The API requires several environment variables to be configured. Create a .env file in the project root:

Required Variables

PORT
number
default:"4000"
Port number where the Express server will listen
NODE_ENV
string
default:"development"
Environment mode: development, production, or testAffects:
  • Error detail exposure (hidden in production)
  • Log verbosity (debug in dev, info in prod)
  • CORS settings
DB_HOST
string
default:"localhost"
PostgreSQL database host address
DB_PORT
number
default:"5432"
PostgreSQL database port
DB_NAME
string
default:"MaqAgr"
PostgreSQL database name
DB_USER
string
default:"postgres"
PostgreSQL database user
DB_PASS
string
required
PostgreSQL database password (REQUIRED)
JWT_SECRET
string
required
Secret key for signing JWT tokens (min 32 characters recommended)Generate a strong secret:
openssl rand -base64 32
JWT_EXPIRES_IN
string
default:"24h"
JWT token expiration timeExamples: 1h, 24h, 7d, 30d
TEST_DB_NAME
string
default:"maqagr_test"
Separate database for integration tests (optional)

Example .env File

.env
# Server Configuration
PORT=4000
NODE_ENV=production

# Database Configuration
DB_HOST=localhost
DB_PORT=5432
DB_NAME=MaqAgr
DB_USER=postgres
DB_PASS=your_secure_password_here

# JWT Configuration
JWT_SECRET=your_super_secure_jwt_secret_min_32_chars_recommended
JWT_EXPIRES_IN=24h

# Redis Configuration (optional)
REDIS_HOST=localhost
REDIS_PORT=6379
Security:
  • Never commit .env files to version control
  • Use strong, randomly generated passwords and secrets
  • Rotate JWT secrets periodically in production
  • Use environment-specific values (separate dev/staging/prod)

Database Setup

Prerequisites

1

Install PostgreSQL

Install PostgreSQL 12 or higher:
sudo apt update
sudo apt install postgresql postgresql-contrib
2

Create Database

Create the production database:
# Connect to PostgreSQL
sudo -u postgres psql

# Create database
CREATE DATABASE MaqAgr;

# Create user (optional)
CREATE USER maqagr_user WITH PASSWORD 'secure_password';
GRANT ALL PRIVILEGES ON DATABASE MaqAgr TO maqagr_user;

# Exit
\q
3

Import Schema

Import the database schema and initial data:
# From project root
psql -d MaqAgr -f docs/dbSetting/users_202601311817.sql
psql -d MaqAgr -f docs/dbSetting/tractor_202601311817.sql
psql -d MaqAgr -f docs/dbSetting/implement_202601311817.sql
psql -d MaqAgr -f docs/dbSetting/terrain_202601311817.sql
psql -d MaqAgr -f database/indexes.sql
If you created a custom user, add the -U flag:
psql -U maqagr_user -d MaqAgr -f docs/dbSetting/users_202601311817.sql
4

Verify Tables

Verify that tables were created:
psql -d MaqAgr

# List all tables
\dt

# Should show:
# - users
# - roles
# - tractors
# - implements
# - terrains
# - calculations
# - recommendations

Database Indexes

Ensure performance indexes are created:
database/indexes.sql
-- User authentication
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_role_id ON users(role_id);

-- Tractors
CREATE INDEX idx_tractors_brand ON tractors(brand);
CREATE INDEX idx_tractors_power ON tractors(power);

-- Terrains
CREATE INDEX idx_terrains_user_id ON terrains(user_id);
CREATE INDEX idx_terrains_soil_type ON terrains(soil_type);

-- Calculations
CREATE INDEX idx_calculations_user_id ON calculations(user_id);
CREATE INDEX idx_calculations_created_at ON calculations(created_at DESC);

Redis Setup (Optional)

Redis is used for caching and rate limiting:
Use the provided docker-compose.yml:
docker-compose.yml
version: '3.8'
services:
  redis:
    image: redis:alpine
    container_name: redis_cache
    restart: always
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

volumes:
  redis_data:
Start Redis:
docker-compose up -d

Installation

1

Clone Repository

git clone https://github.com/David9604/BackMaqagr.git
cd BackMaqagr
2

Install Dependencies

npm install
3

Configure Environment

cp .env.example .env
# Edit .env with your production values
nano .env
4

Setup Database

# Create database and import schema (see Database Setup above)
createdb MaqAgr
psql -d MaqAgr -f docs/dbSetting/users_202601311817.sql
# ... import remaining SQL files
5

Start Server

npm run start

Production Deployment

PM2 is a production process manager for Node.js:
1

Install PM2

npm install -g pm2
2

Start Application

pm2 start src/app.js --name maqagr-api
3

Configure Auto-Restart

# Save PM2 process list
pm2 save

# Generate startup script
pm2 startup
4

Monitor

# View logs
pm2 logs maqagr-api

# Monitor resources
pm2 monit

# View process list
pm2 list

PM2 Ecosystem File

Create ecosystem.config.js for advanced configuration:
ecosystem.config.js
module.exports = {
  apps: [{
    name: 'maqagr-api',
    script: './src/app.js',
    instances: 2,
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 4000
    },
    error_file: './logs/pm2-error.log',
    out_file: './logs/pm2-out.log',
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
    merge_logs: true,
    max_memory_restart: '500M'
  }]
};
Deploy:
pm2 start ecosystem.config.js

Docker Deployment

Create a Dockerfile for containerized deployment:
Dockerfile
FROM node:24-alpine

# Create app directory
WORKDIR /usr/src/app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production

# Copy application code
COPY . .

# Expose port
EXPOSE 4000

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD node -e "require('http').get('http://localhost:4000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"

# Start application
CMD ["node", "src/app.js"]

Full Docker Compose

docker-compose.yml
version: '3.8'

services:
  api:
    build: .
    container_name: maqagr-api
    restart: always
    ports:
      - "4000:4000"
    environment:
      - NODE_ENV=production
      - DB_HOST=postgres
      - DB_PORT=5432
      - DB_NAME=MaqAgr
      - DB_USER=postgres
      - DB_PASS=${DB_PASS}
      - JWT_SECRET=${JWT_SECRET}
      - REDIS_HOST=redis
    depends_on:
      - postgres
      - redis
    networks:
      - maqagr-network

  postgres:
    image: postgres:14-alpine
    container_name: maqagr-postgres
    restart: always
    environment:
      - POSTGRES_DB=MaqAgr
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=${DB_PASS}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./docs/dbSetting:/docker-entrypoint-initdb.d
    networks:
      - maqagr-network

  redis:
    image: redis:alpine
    container_name: maqagr-redis
    restart: always
    volumes:
      - redis_data:/data
    networks:
      - maqagr-network

volumes:
  postgres_data:
  redis_data:

networks:
  maqagr-network:
    driver: bridge
Deploy:
# Build and start all services
docker-compose up -d

# View logs
docker-compose logs -f api

# Stop all services
docker-compose down

Reverse Proxy (Nginx)

Configure Nginx as reverse proxy:
/etc/nginx/sites-available/maqagr-api
server {
    listen 80;
    server_name api.maqagr.com;

    # Redirect to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.maqagr.com;

    # SSL certificates (use Let's Encrypt)
    ssl_certificate /etc/letsencrypt/live/api.maqagr.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.maqagr.com/privkey.pem;

    # 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;

    # API proxy
    location / {
        proxy_pass http://localhost:4000;
        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;
    }

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
    limit_req zone=api_limit burst=20 nodelay;
}
Enable site:
sudo ln -s /etc/nginx/sites-available/maqagr-api /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Health Checks

The API includes a health check endpoint:
curl http://localhost:4000/health
Response:
{
  "status": "ok",
  "timestamp": "2026-03-11T10:30:00.000Z",
  "uptime": 3600,
  "database": "connected",
  "redis": "connected"
}

Monitoring & Logging

Log Files

Logs are stored in the logs/ directory:
logs/
├── combined.log           # All logs
├── error.log              # Errors only
├── app-2026-03-11.log     # Daily rotation
└── app-2026-03-10.log.gz  # Compressed archives

Log Rotation

Logs automatically rotate daily and keep 14 days of history.

Monitoring with PM2

# Real-time monitoring
pm2 monit

# CPU and memory usage
pm2 status

# Application logs
pm2 logs maqagr-api --lines 100

Security Checklist

  • Use strong, randomly generated JWT_SECRET (min 32 chars)
  • Use secure database password
  • Set NODE_ENV=production
  • Never commit .env to version control
  • Use non-default database credentials
  • Enable SSL for database connections in production
  • Regular automated backups
  • Restrict database access to API server only
  • Use HTTPS in production (SSL/TLS certificates)
  • Enable rate limiting (already configured)
  • Configure CORS for specific origins
  • Keep dependencies updated (npm audit)
  • Run as non-root user
  • Configure Nginx/Apache with SSL
  • Enable security headers
  • Set up rate limiting at proxy level
  • Configure firewall rules

Troubleshooting

Check database credentials and connectivity:
# Test PostgreSQL connection
psql -h localhost -U postgres -d MaqAgr

# Check if PostgreSQL is running
sudo systemctl status postgresql

# View API logs
pm2 logs maqagr-api
# Find process using port 4000
lsof -i :4000

# Kill process
kill -9 <PID>

# Or change PORT in .env
# Check if Redis is running
redis-cli ping
# Should return: PONG

# Start Redis
sudo systemctl start redis
# Or with Docker:
docker-compose up -d redis
Configure PM2 memory limit:
pm2 restart maqagr-api --max-memory-restart 500M

Testing

Run tests before deployment

Error Handling

Monitor errors in production

Build docs developers (and LLMs) love