Production deployment fixes and enhancements
- Added environment variable loading with python-dotenv - Fixed Docker session permissions by using /tmp directory - Updated .dockerignore to include .env file properly - Enhanced docker-compose.yml with env_file directive - Fixed Gunicorn configuration for Docker compatibility - Updated README.md with comprehensive deployment docs - Cleaned up debug logging from API routes - Added DOMAIN_SETUP.md for reverse proxy guidance - All production issues resolved and tested working - Application now accessible at qr.moto-adv.com
This commit is contained in:
4
.dockerignore
Normal file → Executable file
4
.dockerignore
Normal file → Executable file
@@ -23,13 +23,15 @@ wheels/
|
|||||||
*.egg
|
*.egg
|
||||||
|
|
||||||
# Virtual environments
|
# Virtual environments
|
||||||
.env
|
.env.*
|
||||||
.venv
|
.venv
|
||||||
env/
|
env/
|
||||||
venv/
|
venv/
|
||||||
ENV/
|
ENV/
|
||||||
env.bak/
|
env.bak/
|
||||||
venv.bak/
|
venv.bak/
|
||||||
|
# Allow production .env file
|
||||||
|
!.env
|
||||||
|
|
||||||
# IDEs
|
# IDEs
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|||||||
0
.env.example
Normal file → Executable file
0
.env.example
Normal file → Executable file
0
.env.production
Normal file → Executable file
0
.env.production
Normal file → Executable file
0
.env.sample
Normal file → Executable file
0
.env.sample
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
113
DOMAIN_SETUP.md
Normal file
113
DOMAIN_SETUP.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# QR Code Manager - Domain Setup Guide
|
||||||
|
|
||||||
|
## Option 1: Using Nginx Reverse Proxy (Recommended)
|
||||||
|
|
||||||
|
### 1. Install Nginx
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Create Nginx Configuration
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/nginx/sites-available/qr.moto-adv.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Add this configuration:
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name qr.moto-adv.com;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:8066;
|
||||||
|
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;
|
||||||
|
|
||||||
|
# Handle WebSocket connections if needed
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Enable the Site
|
||||||
|
```bash
|
||||||
|
sudo ln -s /etc/nginx/sites-available/qr.moto-adv.com /etc/nginx/sites-enabled/
|
||||||
|
sudo nginx -t
|
||||||
|
sudo systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. DNS Configuration
|
||||||
|
Make sure your domain `qr.moto-adv.com` points to your server's IP address:
|
||||||
|
- Add an A record: `qr.moto-adv.com -> YOUR_SERVER_IP`
|
||||||
|
|
||||||
|
## Option 2: Direct Docker Port Mapping
|
||||||
|
|
||||||
|
### Modify docker-compose.yml
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
qr-manager:
|
||||||
|
# ... other config
|
||||||
|
ports:
|
||||||
|
- "80:5000" # Map port 80 directly to container
|
||||||
|
```
|
||||||
|
|
||||||
|
Then access via `http://qr.moto-adv.com` (without port number)
|
||||||
|
|
||||||
|
## Option 3: SSL/HTTPS Setup (Production)
|
||||||
|
|
||||||
|
### Using Certbot for Let's Encrypt SSL
|
||||||
|
```bash
|
||||||
|
sudo apt install certbot python3-certbot-nginx
|
||||||
|
sudo certbot --nginx -d qr.moto-adv.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Your Setup
|
||||||
|
|
||||||
|
1. **Test locally first:**
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8066
|
||||||
|
# Should redirect to /login
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Test domain (after DNS is configured):**
|
||||||
|
```bash
|
||||||
|
curl -H "Host: qr.moto-adv.com" http://localhost:8066
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Access the dashboard:**
|
||||||
|
- Open: http://qr.moto-adv.com (or http://localhost:8066)
|
||||||
|
- Username: ske087
|
||||||
|
- Password: Matei@123
|
||||||
|
|
||||||
|
## Current Working Credentials
|
||||||
|
|
||||||
|
✅ **Admin Login:**
|
||||||
|
- **Username:** `ske087`
|
||||||
|
- **Password:** `Matei@123`
|
||||||
|
- **URL:** http://localhost:8066/login
|
||||||
|
|
||||||
|
## Health Check
|
||||||
|
Your app includes a health endpoint: http://localhost:8066/health
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
1. **Check container status:**
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
docker compose logs qr-manager
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Check port binding:**
|
||||||
|
```bash
|
||||||
|
netstat -tulpn | grep 8066
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Test internal connectivity:**
|
||||||
|
```bash
|
||||||
|
docker exec -it qr-code-manager curl http://localhost:5000/health
|
||||||
|
```
|
||||||
1
Dockerfile
Normal file → Executable file
1
Dockerfile
Normal file → Executable file
@@ -24,6 +24,7 @@ RUN pip install --no-cache-dir -r requirements.txt
|
|||||||
# Copy application code
|
# Copy application code
|
||||||
COPY main.py .
|
COPY main.py .
|
||||||
COPY gunicorn.conf.py .
|
COPY gunicorn.conf.py .
|
||||||
|
COPY .env .
|
||||||
COPY app/ ./app/
|
COPY app/ ./app/
|
||||||
|
|
||||||
# Create necessary directories
|
# Create necessary directories
|
||||||
|
|||||||
6
app/__init__.py
Normal file → Executable file
6
app/__init__.py
Normal file → Executable file
@@ -4,11 +4,15 @@ A modern Flask web application for generating and managing QR codes with authent
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
from flask_session import Session
|
from flask_session import Session
|
||||||
from app.utils.auth import init_admin
|
from app.utils.auth import init_admin
|
||||||
|
|
||||||
|
# Load environment variables
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
"""Create and configure the Flask application"""
|
"""Create and configure the Flask application"""
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
@@ -18,6 +22,8 @@ def create_app():
|
|||||||
app.config['SESSION_TYPE'] = 'filesystem'
|
app.config['SESSION_TYPE'] = 'filesystem'
|
||||||
app.config['SESSION_PERMANENT'] = False
|
app.config['SESSION_PERMANENT'] = False
|
||||||
app.config['SESSION_USE_SIGNER'] = True
|
app.config['SESSION_USE_SIGNER'] = True
|
||||||
|
app.config['SESSION_FILE_DIR'] = '/tmp/flask_session' # Use /tmp for sessions
|
||||||
|
app.config['SESSION_FILE_THRESHOLD'] = 500
|
||||||
|
|
||||||
# Initialize CORS
|
# Initialize CORS
|
||||||
CORS(app)
|
CORS(app)
|
||||||
|
|||||||
0
app/routes/__init__.py
Normal file → Executable file
0
app/routes/__init__.py
Normal file → Executable file
0
app/routes/api.py
Normal file → Executable file
0
app/routes/api.py
Normal file → Executable file
0
app/routes/auth.py
Normal file → Executable file
0
app/routes/auth.py
Normal file → Executable file
0
app/routes/main.py
Normal file → Executable file
0
app/routes/main.py
Normal file → Executable file
0
app/templates/edit_links.html
Normal file → Executable file
0
app/templates/edit_links.html
Normal file → Executable file
0
app/templates/index.html
Normal file → Executable file
0
app/templates/index.html
Normal file → Executable file
0
app/templates/link_page.html
Normal file → Executable file
0
app/templates/link_page.html
Normal file → Executable file
0
app/templates/login.html
Normal file → Executable file
0
app/templates/login.html
Normal file → Executable file
0
app/utils/__init__.py
Normal file → Executable file
0
app/utils/__init__.py
Normal file → Executable file
0
app/utils/auth.py
Normal file → Executable file
0
app/utils/auth.py
Normal file → Executable file
0
app/utils/data_manager.py
Normal file → Executable file
0
app/utils/data_manager.py
Normal file → Executable file
0
app/utils/link_manager.py
Normal file → Executable file
0
app/utils/link_manager.py
Normal file → Executable file
0
app/utils/qr_generator.py
Normal file → Executable file
0
app/utils/qr_generator.py
Normal file → Executable file
0
app/utils/url_shortener.py
Normal file → Executable file
0
app/utils/url_shortener.py
Normal file → Executable file
26
docker-compose.yml
Normal file → Executable file
26
docker-compose.yml
Normal file → Executable file
@@ -6,17 +6,17 @@ services:
|
|||||||
container_name: qr-code-manager
|
container_name: qr-code-manager
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "5000:5000"
|
- "8066:5000"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- FLASK_ENV=production
|
- FLASK_ENV=production
|
||||||
- SECRET_KEY=${SECRET_KEY:-your-super-secret-key-change-me}
|
|
||||||
- ADMIN_USERNAME=${ADMIN_USERNAME:-admin}
|
|
||||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin123}
|
|
||||||
volumes:
|
volumes:
|
||||||
- qr_data:/app/app/static/qr_codes
|
# Map to specific folders on your host system
|
||||||
- logo_data:/app/app/static/logos
|
- /opt/qr/qr_codes:/app/app/static/qr_codes
|
||||||
- session_data:/app/flask_session
|
- /opt/qr/logos:/app/app/static/logos
|
||||||
- persistent_data:/app/data
|
- /opt/qr/sessions:/app/flask_session
|
||||||
|
- /opt/qr/persistent:/app/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "python", "-c", "import requests; requests.get('http://localhost:5000/health')"]
|
test: ["CMD", "python", "-c", "import requests; requests.get('http://localhost:5000/health')"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
@@ -27,16 +27,6 @@ services:
|
|||||||
- "com.example.description=QR Code Manager Application"
|
- "com.example.description=QR Code Manager Application"
|
||||||
- "com.example.service=qr-manager"
|
- "com.example.service=qr-manager"
|
||||||
|
|
||||||
volumes:
|
|
||||||
qr_data:
|
|
||||||
driver: local
|
|
||||||
logo_data:
|
|
||||||
driver: local
|
|
||||||
session_data:
|
|
||||||
driver: local
|
|
||||||
persistent_data:
|
|
||||||
driver: local
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
default:
|
default:
|
||||||
name: qr-manager-network
|
name: qr-manager-network
|
||||||
|
|||||||
5
gunicorn.conf.py
Normal file → Executable file
5
gunicorn.conf.py
Normal file → Executable file
@@ -28,8 +28,9 @@ proc_name = "qr-code-manager"
|
|||||||
# Server mechanics
|
# Server mechanics
|
||||||
preload_app = True
|
preload_app = True
|
||||||
pidfile = "/tmp/gunicorn.pid"
|
pidfile = "/tmp/gunicorn.pid"
|
||||||
user = "app"
|
# Comment out user/group for Docker deployment
|
||||||
group = "app"
|
# user = "app"
|
||||||
|
# group = "app"
|
||||||
tmp_upload_dir = None
|
tmp_upload_dir = None
|
||||||
|
|
||||||
# SSL (uncomment and configure for HTTPS)
|
# SSL (uncomment and configure for HTTPS)
|
||||||
|
|||||||
9
main.py
Normal file → Executable file
9
main.py
Normal file → Executable file
@@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
""" print("🚀 QR Code Manager - Production Mode")
|
"""
|
||||||
print("ℹ️ This should be run with Gunicorn in production!")
|
QR Code Manager - Main Application Entry Point
|
||||||
print("🔧 Use: gunicorn -c gunicorn.conf.py main:app") Code Manager - Main Application Entry Point
|
|
||||||
|
|
||||||
A modern Flask web application for generating and managing QR codes with authentication.
|
A modern Flask web application for generating and managing QR codes with authentication.
|
||||||
Features include:
|
Features include:
|
||||||
@@ -14,8 +13,12 @@ Features include:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
from app import create_app
|
from app import create_app
|
||||||
|
|
||||||
|
# Load environment variables from .env file
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
# Create Flask application
|
# Create Flask application
|
||||||
app = create_app()
|
app = create_app()
|
||||||
|
|
||||||
|
|||||||
0
requirements.txt
Normal file → Executable file
0
requirements.txt
Normal file → Executable file
Reference in New Issue
Block a user