Overview
This guide covers deploying Aqua-IoT to a production environment. We’ll use industry-standard tools and practices to ensure a secure, performant, and reliable deployment.
Important : Never deploy the application with default settings. Always configure security settings, use environment variables for secrets, and disable debug mode.
Production Architecture
A typical production deployment includes:
Web Server : Nginx or Apache for serving static files and reverse proxy
Application Server : Gunicorn or uWSGI for running Django
Database : PostgreSQL for data persistence
MQTT Broker : Mosquitto or HiveMQ for IoT communication
Process Manager : Systemd or Supervisor for service management
Prerequisites
Before deploying to production:
A server running Linux (Ubuntu 20.04+ or similar)
Root or sudo access
Domain name (optional but recommended)
SSL certificate (Let’s Encrypt recommended)
Production Setup Steps
Prepare the Server
Update system packages and install dependencies: # Update package list
sudo apt update && sudo apt upgrade -y
# Install required packages
sudo apt install -y python3-pip python3-venv postgresql nginx supervisor
Configure PostgreSQL
Set up the production database: # Switch to postgres user
sudo -u postgres psql
In the PostgreSQL shell: -- Create database
CREATE DATABASE aqua_production ;
-- Create user with strong password
CREATE USER aqua_user WITH PASSWORD 'your_secure_password_here' ;
-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE aqua_production TO aqua_user;
-- Exit
\q
Deploy Application Code
Clone and set up the application: # Create application directory
sudo mkdir -p /var/www/aqua-iot
sudo chown $USER : $USER /var/www/aqua-iot
# Clone repository
cd /var/www/aqua-iot
git clone https://github.com/barrancocarlos/Aqua-IoT.git .
# Navigate to Django directory
cd Django
# Set up virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install --upgrade pip
pip install django djangorestframework psycopg2-binary gunicorn
Configure Environment Variables
Create a secure environment configuration: # Create .env file
nano /var/www/aqua-iot/Django/.env
Add the following variables: DJANGO_SECRET_KEY = your-generated-secret-key
DJANGO_DEBUG = False
DJANGO_ALLOWED_HOSTS = yourdomain.com,www.yourdomain.com,server-ip
DB_NAME = aqua_production
DB_USER = aqua_user
DB_PASSWORD = your_secure_password_here
DB_HOST = localhost
DB_PORT = 5432
MQTT_BROKER_HOST = localhost
MQTT_BROKER_PORT = 1883
Generate a secure secret key: python - c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
Update Django Settings
Modify settings.py to use environment variables: Django/painel/settings.py
import os
from pathlib import Path
# Load environment variables
DEBUG = os.environ.get( 'DJANGO_DEBUG' , 'False' ) == 'True'
SECRET_KEY = os.environ.get( 'DJANGO_SECRET_KEY' )
ALLOWED_HOSTS = os.environ.get( 'DJANGO_ALLOWED_HOSTS' , '' ).split( ',' )
# Database configuration
DATABASES = {
'default' : {
'ENGINE' : 'django.db.backends.postgresql_psycopg2' ,
'NAME' : os.environ.get( 'DB_NAME' ),
'USER' : os.environ.get( 'DB_USER' ),
'PASSWORD' : os.environ.get( 'DB_PASSWORD' ),
'HOST' : os.environ.get( 'DB_HOST' , 'localhost' ),
'PORT' : os.environ.get( 'DB_PORT' , '5432' ),
}
}
Run Database Migrations
Set up the database schema: # Load environment variables
export $( cat .env | xargs )
# Run migrations
python manage.py migrate
# Create superuser
python manage.py createsuperuser
# Collect static files
python manage.py collectstatic --noinput
Configure Gunicorn
Set up Gunicorn as the application server: # Create Gunicorn configuration
nano /var/www/aqua-iot/Django/gunicorn_config.py
Add the configuration: import multiprocessing
bind = "127.0.0.1:8000"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "sync"
timeout = 120
keepalive = 5
errorlog = "/var/log/aqua-iot/gunicorn-error.log"
accesslog = "/var/log/aqua-iot/gunicorn-access.log"
loglevel = "info"
Create log directory: sudo mkdir -p /var/log/aqua-iot
sudo chown $USER : $USER /var/log/aqua-iot
Configure Supervisor
Create a Supervisor configuration to manage the Gunicorn process: sudo nano /etc/supervisor/conf.d/aqua-iot.conf
Add the configuration: /etc/supervisor/conf.d/aqua-iot.conf
[program:aqua-iot]
command =/var/www/aqua-iot/Django/venv/bin/gunicorn painel.wsgi:application -c /var/www/aqua-iot/Django/gunicorn_config.py
directory =/var/www/aqua-iot/Django
user =www-data
autostart =true
autorestart =true
redirect_stderr =true
stdout_logfile =/var/log/aqua-iot/supervisor.log
environment = PATH = "/var/www/aqua-iot/Django/venv/bin" , DJANGO_SECRET_KEY = "your-secret-key" , DJANGO_DEBUG = "False" , DB_NAME = "aqua_production" , DB_USER = "aqua_user" , DB_PASSWORD = "your_password" , DB_HOST = "localhost" , DB_PORT = "5432"
Start Supervisor: sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start aqua-iot
Configure Nginx
Set up Nginx as a reverse proxy: sudo nano /etc/nginx/sites-available/aqua-iot
Add the Nginx configuration: /etc/nginx/sites-available/aqua-iot
upstream aqua_app {
server 127.0.0.1:8000 fail_timeout = 0 ;
}
server {
listen 80 ;
server_name yourdomain.com www.yourdomain.com;
client_max_body_size 4G ;
access_log /var/log/nginx/aqua-iot-access.log;
error_log /var/log/nginx/aqua-iot-error.log;
# Static files
location /static/ {
alias /var/www/aqua-iot/Django/static_files/;
expires 30d ;
add_header Cache-Control "public, immutable" ;
}
# Media files
location /media/ {
alias /var/www/aqua-iot/Django/static_media/;
}
# Proxy to Gunicorn
location / {
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $ scheme ;
proxy_set_header Host $ http_host ;
proxy_redirect off ;
proxy_pass http://aqua_app;
}
}
Enable the site: sudo ln -s /etc/nginx/sites-available/aqua-iot /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
Configure SSL with Let's Encrypt
Secure your site with HTTPS: # Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Obtain certificate
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Test auto-renewal
sudo certbot renew --dry-run
Configure MQTT Broker
Set up Mosquitto for IoT communication: # Install Mosquitto
sudo apt install mosquitto mosquitto-clients -y
# Configure authentication
sudo mosquitto_passwd -c /etc/mosquitto/passwd mqtt_user
# Edit configuration
sudo nano /etc/mosquitto/mosquitto.conf
Add security settings: /etc/mosquitto/mosquitto.conf
allow_anonymous false
password_file /etc/mosquitto/passwd
listener 1883 localhost
Restart Mosquitto: sudo systemctl restart mosquitto
sudo systemctl enable mosquitto
Security Hardening
Firewall Configuration
Configure UFW to allow only necessary ports:
# Enable firewall
sudo ufw enable
# Allow SSH (be careful!)
sudo ufw allow 22/tcp
# Allow HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Check status
sudo ufw status
Additional Security Measures
Ensure CSRF middleware is enabled in settings.py: MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware' ,
# ... other middleware
]
Add these settings for production: SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Set up automated PostgreSQL backups: # Create backup script
sudo nano /usr/local/bin/backup-aqua-db.sh
Add: #!/bin/bash
DATE = $( date +%Y%m%d_%H%M%S )
pg_dump -U aqua_user aqua_production > /backups/aqua_ $DATE .sql
find /backups -name "aqua_*.sql" -mtime +7 -delete
Make executable and add to cron: sudo chmod +x /usr/local/bin/backup-aqua-db.sh
sudo crontab -e
# Add: 0 2 * * * /usr/local/bin/backup-aqua-db.sh
Monitoring and Maintenance
Application Logs
Monitor application logs:
# Supervisor logs
sudo tail -f /var/log/aqua-iot/supervisor.log
# Gunicorn error logs
sudo tail -f /var/log/aqua-iot/gunicorn-error.log
# Nginx logs
sudo tail -f /var/log/nginx/aqua-iot-error.log
Service Management
# Restart application
sudo supervisorctl restart aqua-iot
# Restart Nginx
sudo systemctl restart nginx
# Check service status
sudo supervisorctl status
sudo systemctl status nginx
sudo systemctl status postgresql
sudo systemctl status mosquitto
Updating the Application
# Navigate to application directory
cd /var/www/aqua-iot
# Pull latest changes
git pull origin main
# Activate virtual environment
cd Django
source venv/bin/activate
# Install new dependencies
pip install -r requirements.txt
# Run migrations
python manage.py migrate
# Collect static files
python manage.py collectstatic --noinput
# Restart application
sudo supervisorctl restart aqua-iot
Database Optimization
-- Create indexes for frequently queried fields
CREATE INDEX idx_sensor_timestamp ON sensor_data( timestamp );
CREATE INDEX idx_sensor_type ON sensor_data(sensor_type);
-- Vacuum and analyze
VACUUM ANALYZE;
Static File Compression
Enable gzip compression in Nginx:
gzip on ;
gzip_vary on ;
gzip_min_length 1024 ;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;
Caching
Consider implementing Redis for caching:
sudo apt install redis-server -y
pip install django-redis
Troubleshooting
Check if Gunicorn is running: sudo supervisorctl status aqua-iot
sudo supervisorctl restart aqua-iot
Verify static file permissions: sudo chown -R www-data:www-data /var/www/aqua-iot/Django/static_files
python manage.py collectstatic --noinput
Database connection errors
Check PostgreSQL status and credentials: sudo systemctl status postgresql
sudo -u postgres psql -c "\du"
Test MQTT broker: mosquitto_sub -h localhost -t test/topic -u mqtt_user -P password
Production Checklist
Before going live:
Next Steps
API Reference Explore the REST API endpoints
Arduino Integration Connect Arduino sensors to your system