GUI Deployment Guide
====================
This guide covers deploying the py3plex web interface for production use.
Overview
--------
The py3plex GUI can be deployed in several ways:
1. **Local Development** - Run directly on your machine
2. **Docker Container** - Isolated, reproducible environment
3. **Production Server** - Behind reverse proxy with TLS
4. **Cloud Deployment** - AWS, Azure, GCP, etc.
See :doc:`gui_user_guide` for basic usage and :doc:`gui_architecture` for technical details.
Local Development Setup
-----------------------
Quick Start
~~~~~~~~~~~
.. code-block:: bash
# Clone repository
git clone https://github.com/SkBlaz/py3plex.git
cd py3plex
# Install with GUI dependencies
pip install -e ".[gui]"
# Start development server
python gui/app.py
The GUI will be available at ``http://localhost:5000``.
Configuration
~~~~~~~~~~~~~
Create a configuration file ``gui/config.py``:
.. code-block:: python
# Development configuration
DEBUG = True
HOST = '0.0.0.0'
PORT = 5000
SECRET_KEY = 'dev-secret-key-change-in-production'
# Upload settings
UPLOAD_FOLDER = './uploads'
MAX_CONTENT_LENGTH = 100 * 1024 * 1024 # 100 MB max file size
# Allowed file extensions
ALLOWED_EXTENSIONS = {'txt', 'edgelist', 'graphml', 'gml', 'json', 'arrow'}
Docker Deployment
-----------------
Basic Docker Setup
~~~~~~~~~~~~~~~~~~
The repository includes a Dockerfile for the GUI:
.. code-block:: bash
# Build image
docker build -t py3plex-gui:latest -f gui/Dockerfile .
# Run container
docker run -d \
-p 5000:5000 \
-v $(pwd)/data:/app/data \
--name py3plex-gui \
py3plex-gui:latest
The GUI will be available at ``http://localhost:5000``.
Docker Compose
~~~~~~~~~~~~~~
Create ``docker-compose.yml``:
.. code-block:: yaml
version: '3.8'
services:
gui:
build:
context: .
dockerfile: gui/Dockerfile
ports:
- "5000:5000"
volumes:
- ./data:/app/data
- ./uploads:/app/uploads
environment:
- FLASK_ENV=production
- SECRET_KEY=${SECRET_KEY}
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 10s
retries: 3
Start with:
.. code-block:: bash
# Set secret key
export SECRET_KEY=$(python -c 'import secrets; print(secrets.token_hex(32))')
# Start services
docker-compose up -d
# Check logs
docker-compose logs -f gui
Environment Variables
~~~~~~~~~~~~~~~~~~~~~
Configure via environment variables:
.. list-table::
:header-rows: 1
:widths: 30 40 30
* - Variable
- Description
- Default
* - ``FLASK_ENV``
- Environment (development/production)
- development
* - ``SECRET_KEY``
- Session secret key (required)
- None
* - ``HOST``
- Bind address
- 0.0.0.0
* - ``PORT``
- Bind port
- 5000
* - ``MAX_WORKERS``
- Worker processes
- 4
* - ``UPLOAD_FOLDER``
- Upload directory
- ./uploads
* - ``DATA_FOLDER``
- Data directory
- ./data
Production Deployment
---------------------
Using Gunicorn
~~~~~~~~~~~~~~
For production, use a production WSGI server like Gunicorn:
.. code-block:: bash
# Install Gunicorn
pip install gunicorn
# Run with Gunicorn
gunicorn \
--bind 0.0.0.0:5000 \
--workers 4 \
--timeout 120 \
--access-logfile - \
--error-logfile - \
gui.app:app
Supervisor Configuration
~~~~~~~~~~~~~~~~~~~~~~~~
Use Supervisor to manage the GUI process:
Create ``/etc/supervisor/conf.d/py3plex-gui.conf``:
.. code-block:: ini
[program:py3plex-gui]
command=/path/to/venv/bin/gunicorn --bind 127.0.0.1:5000 --workers 4 gui.app:app
directory=/path/to/py3plex
user=www-data
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/py3plex-gui.log
environment=FLASK_ENV="production",SECRET_KEY="your-secret-key"
Start with:
.. code-block:: bash
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start py3plex-gui
Systemd Service
~~~~~~~~~~~~~~~
Alternative: use systemd:
Create ``/etc/systemd/system/py3plex-gui.service``:
.. code-block:: ini
[Unit]
Description=Py3plex GUI
After=network.target
[Service]
Type=notify
User=www-data
WorkingDirectory=/path/to/py3plex
Environment="FLASK_ENV=production"
Environment="SECRET_KEY=your-secret-key"
ExecStart=/path/to/venv/bin/gunicorn --bind 127.0.0.1:5000 --workers 4 gui.app:app
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Enable and start:
.. code-block:: bash
sudo systemctl daemon-reload
sudo systemctl enable py3plex-gui
sudo systemctl start py3plex-gui
sudo systemctl status py3plex-gui
Reverse Proxy Setup
-------------------
Nginx Configuration
~~~~~~~~~~~~~~~~~~~
Configure Nginx as a reverse proxy:
Create ``/etc/nginx/sites-available/py3plex-gui``:
.. code-block:: nginx
server {
listen 80;
server_name py3plex.yourdomain.com;
# Redirect to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name py3plex.yourdomain.com;
# SSL certificates (use Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/py3plex.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/py3plex.yourdomain.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;
# Upload size limit
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:5000;
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;
# Timeouts for long-running operations
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
# Static files (if serving separately)
location /static {
alias /path/to/py3plex/gui/static;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
Enable the site:
.. code-block:: bash
sudo ln -s /etc/nginx/sites-available/py3plex-gui /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Apache Configuration
~~~~~~~~~~~~~~~~~~~~
Alternative: use Apache as reverse proxy:
.. code-block:: apache
ServerName py3plex.yourdomain.com
Redirect permanent / https://py3plex.yourdomain.com/
ServerName py3plex.yourdomain.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/py3plex.yourdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/py3plex.yourdomain.com/privkey.pem
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:5000/
ProxyPassReverse / http://127.0.0.1:5000/
# Security headers
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
SSL/TLS with Let's Encrypt
~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
# Install certbot
sudo apt-get install certbot python3-certbot-nginx
# Obtain certificate
sudo certbot --nginx -d py3plex.yourdomain.com
# Auto-renewal (certbot sets this up automatically)
sudo certbot renew --dry-run
Security Considerations
-----------------------
Secret Key Management
~~~~~~~~~~~~~~~~~~~~~
**Never** hardcode secret keys in code or configuration files:
.. code-block:: bash
# Generate strong secret key
python -c 'import secrets; print(secrets.token_hex(32))' > .secret_key
# Set in environment
export SECRET_KEY=$(cat .secret_key)
# Or use environment file
echo "SECRET_KEY=$(python -c 'import secrets; print(secrets.token_hex(32))')" > .env
File Upload Security
~~~~~~~~~~~~~~~~~~~~
Configure upload restrictions:
.. code-block:: python
# In config.py
ALLOWED_EXTENSIONS = {'txt', 'edgelist', 'graphml', 'gml', 'json', 'arrow'}
MAX_CONTENT_LENGTH = 100 * 1024 * 1024 # 100 MB
# Validate uploads
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
Rate Limiting
~~~~~~~~~~~~~
Implement rate limiting for API endpoints:
.. code-block:: python
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(
app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)
@app.route("/api/upload")
@limiter.limit("10 per hour")
def upload():
pass
Authentication
~~~~~~~~~~~~~~
Add user authentication for production:
.. code-block:: python
from flask_login import LoginManager, login_required
login_manager = LoginManager()
login_manager.init_app(app)
@app.route("/dashboard")
@login_required
def dashboard():
pass
Monitoring and Logging
----------------------
Application Logging
~~~~~~~~~~~~~~~~~~~
Configure structured logging:
.. code-block:: python
import logging
from logging.handlers import RotatingFileHandler
# Configure logging
handler = RotatingFileHandler(
'logs/py3plex-gui.log',
maxBytes=10 * 1024 * 1024, # 10 MB
backupCount=5
)
handler.setFormatter(logging.Formatter(
'[%(asctime)s] %(levelname)s in %(module)s: %(message)s'
))
app.logger.addHandler(handler)
app.logger.setLevel(logging.INFO)
Prometheus Metrics
~~~~~~~~~~~~~~~~~~
Export metrics for Prometheus:
.. code-block:: python
from prometheus_flask_exporter import PrometheusMetrics
metrics = PrometheusMetrics(app)
# Custom metrics
metrics.info('app_info', 'Application info', version='1.0')
Health Checks
~~~~~~~~~~~~~
Implement health check endpoint:
.. code-block:: python
@app.route('/health')
def health():
# Check dependencies
try:
# Test database connection, file system, etc.
return {'status': 'healthy'}, 200
except Exception as e:
return {'status': 'unhealthy', 'error': str(e)}, 503
Cloud Deployment Examples
--------------------------
AWS EC2
~~~~~~~
1. Launch EC2 instance (Ubuntu 22.04 LTS)
2. Install dependencies
3. Clone repository
4. Follow production deployment steps above
5. Configure security groups (ports 80, 443)
AWS ECS (Docker)
~~~~~~~~~~~~~~~~
.. code-block:: json
{
"family": "py3plex-gui",
"containerDefinitions": [{
"name": "gui",
"image": "your-registry/py3plex-gui:latest",
"memory": 2048,
"cpu": 1024,
"essential": true,
"portMappings": [{
"containerPort": 5000,
"protocol": "tcp"
}],
"environment": [
{"name": "FLASK_ENV", "value": "production"}
],
"secrets": [
{"name": "SECRET_KEY", "valueFrom": "arn:aws:secretsmanager:..."}
]
}]
}
Google Cloud Run
~~~~~~~~~~~~~~~~
.. code-block:: bash
# Build and push to GCR
gcloud builds submit --tag gcr.io/PROJECT_ID/py3plex-gui
# Deploy
gcloud run deploy py3plex-gui \
--image gcr.io/PROJECT_ID/py3plex-gui \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars FLASK_ENV=production \
--set-secrets SECRET_KEY=py3plex-secret:latest
Azure Container Instances
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
# Create container group
az container create \
--resource-group py3plex-rg \
--name py3plex-gui \
--image your-registry.azurecr.io/py3plex-gui:latest \
--dns-name-label py3plex-gui \
--ports 5000 \
--environment-variables FLASK_ENV=production \
--secure-environment-variables SECRET_KEY=$SECRET_KEY
Performance Tuning
------------------
Worker Configuration
~~~~~~~~~~~~~~~~~~~~
.. code-block:: bash
# Rule of thumb: (2 x CPU cores) + 1
workers=$((2 * $(nproc) + 1))
gunicorn \
--workers $workers \
--threads 2 \
--worker-class gthread \
--timeout 120 \
--bind 0.0.0.0:5000 \
gui.app:app
Caching
~~~~~~~
Implement caching for expensive operations:
.. code-block:: python
from flask_caching import Cache
cache = Cache(app, config={'CACHE_TYPE': 'simple'})
@app.route('/api/stats/')
@cache.cached(timeout=300)
def network_stats(network_id):
# Expensive computation
return stats
Database for Persistence
~~~~~~~~~~~~~~~~~~~~~~~~~
For production, consider a database:
.. code-block:: python
from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:pass@localhost/py3plex'
db = SQLAlchemy(app)
Backup and Recovery
-------------------
Automated Backups
~~~~~~~~~~~~~~~~~
.. code-block:: bash
#!/bin/bash
# backup.sh
BACKUP_DIR="/backups/py3plex"
DATE=$(date +%Y%m%d_%H%M%S)
# Backup uploads
tar -czf "$BACKUP_DIR/uploads_$DATE.tar.gz" /path/to/uploads
# Backup database (if using one)
# pg_dump py3plex > "$BACKUP_DIR/db_$DATE.sql"
# Cleanup old backups (keep last 7 days)
find "$BACKUP_DIR" -type f -mtime +7 -delete
Add to crontab:
.. code-block:: bash
# Daily backup at 2 AM
0 2 * * * /path/to/backup.sh
Disaster Recovery
~~~~~~~~~~~~~~~~~
Document recovery procedure:
1. Restore from backup
2. Verify data integrity
3. Restart services
4. Test functionality
Troubleshooting
---------------
Common Issues
~~~~~~~~~~~~~
**Port already in use:**
.. code-block:: bash
# Find process using port
sudo lsof -i :5000
# Kill process
sudo kill -9 PID
**Permission denied:**
.. code-block:: bash
# Fix upload directory permissions
sudo chown -R www-data:www-data /path/to/uploads
**Out of memory:**
.. code-block:: bash
# Check memory usage
free -h
# Adjust worker count or add swap
Logs Location
~~~~~~~~~~~~~
* Application logs: ``/var/log/py3plex-gui.log``
* Nginx logs: ``/var/log/nginx/``
* Systemd logs: ``journalctl -u py3plex-gui``
Related Documentation
---------------------
* :doc:`gui_user_guide` - Using the GUI
* :doc:`gui_architecture` - Technical architecture
* :doc:`gui_api_reference` - API endpoints
* :doc:`gui_testing` - Testing the GUI
* :doc:`../deployment/cli_and_docker` - Docker details
**Security Resources:**
* OWASP Flask Security: https://owasp.org/www-project-web-security-testing-guide/
* Flask Security Best Practices: https://flask.palletsprojects.com/en/2.3.x/security/