QR Code Manager
A modern Flask web application for generating and managing QR codes with authentication and dynamic link pages.
🚀 Features
- Multiple QR Code Types: Text, URL, WiFi, Email, SMS, vCard
- Dynamic Link Pages: Create collections of links accessible via QR codes
- URL Shortener: Generate shortened URLs with custom domains and QR codes
- Admin Authentication: Secure login with bcrypt password hashing
- Customizable Styling: Different QR code styles (square, rounded, circle)
- Logo Integration: Add custom logos to QR codes
- Click Tracking: Monitor short URL usage and statistics
- 🆕 Comprehensive Backup System: Full backup lifecycle management
- Create backups on-demand or automated
- Download, delete, and cleanup old backups
- Web-based backup management interface
- Docker-aware backup operations
- Docker Deployment: Production-ready containerization
- Responsive Design: Modern web interface that works on all devices
📁 Project Structure
qr-code_manager/
├── README.md # Project documentation
├── main.py # Application entry point
├── Dockerfile # Docker container definition
├── docker-compose.yml # Docker orchestration
├── requirements.txt # Python dependencies
├── .env.example # Environment variables template
├── deploy.sh # Deployment script
├── app/ # Main application package
│ ├── __init__.py # Flask app factory
│ ├── templates/ # Jinja2 templates
│ │ ├── index.html # Main dashboard
│ │ ├── login.html # Authentication page
│ │ ├── link_page.html # Public link display
│ │ └── edit_links.html # Link management interface
│ ├── static/ # Static files
│ │ ├── qr_codes/ # Generated QR code images
│ │ └── logos/ # Uploaded logo files
│ ├── routes/ # Route handlers
│ │ ├── __init__.py # Route package
│ │ ├── main.py # Main page routes
│ │ ├── auth.py # Authentication routes
│ │ └── api.py # API endpoints
│ └── utils/ # Utility modules
│ ├── __init__.py # Utils package
│ ├── auth.py # Authentication utilities
│ ├── qr_generator.py # QR code generation
│ ├── link_manager.py # Dynamic link management
│ ├── url_shortener.py # URL shortening utilities
│ └── data_manager.py # Data storage utilities
🛠️ Quick Start
Method 1: Docker (Recommended)
-
Clone and navigate to the project:
git clone <your-repo-url> cd qr-code_manager -
Create environment file:
cp .env.example .env # Edit .env with your preferred settings -
Deploy with Docker:
./deploy.sh -
Access the application:
- Open http://localhost:5000
- Login with: admin / admin123 (change in production!)
Method 2: Local Development
-
Set up Python environment:
python -m venv .venv source .venv/bin/activate # On Windows: .venv\Scripts\activate -
Install dependencies:
pip install -r requirements.txt -
Run the application:
python main.py
<EFBFBD> Production vs Development Modes
The QR Code Manager supports two distinct runtime modes with different behaviors and optimizations.
🛠️ Development Mode (Default)
When it runs:
- When
FLASK_ENVis not set to "production" - When running
python main.pylocally - Default mode for local development
Characteristics:
- Uses Flask's built-in development server
- Debug mode enabled with auto-reload
- Detailed error messages and stack traces
- Console shows default login credentials
- Not suitable for production use
How to run:
# Method 1: Direct execution
python main.py
# Method 2: With explicit development environment
FLASK_ENV=development python main.py
# Method 3: Using environment file
echo "FLASK_ENV=development" > .env
python main.py
Console output in development:
🛠️ Starting QR Code Manager in DEVELOPMENT mode
🔐 Admin user: admin
🔑 Default password: admin123
🌐 Domain configured: localhost:5000
🔗 URL shortener available at: /s/
* Serving Flask app 'app'
* Debug mode: on
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
🚀 Production Mode
When it runs:
- When
FLASK_ENV=productionis set - When deployed with Docker (automatic)
- For live/production deployments
Characteristics:
- Uses Gunicorn WSGI server (4 workers)
- Debug mode disabled
- Optimized for performance and security
- No default credentials shown
- Production-grade error handling
How to run:
Option 1: Docker (Recommended)
# Copy and edit production environment
cp .env.production .env
# Edit .env with your production settings
# Deploy with Docker
docker-compose up -d
Option 2: Manual Gunicorn
# Set production environment
export FLASK_ENV=production
export SECRET_KEY=your-super-secret-key
export ADMIN_USERNAME=your-admin-username
export ADMIN_PASSWORD=your-secure-password
export APP_DOMAIN=your-domain.com
# Run with Gunicorn
gunicorn -c gunicorn.conf.py main:app
Option 3: Environment File + Gunicorn
# Create production environment file
cp .env.production .env
# Edit .env with your settings:
# FLASK_ENV=production
# SECRET_KEY=your-super-secret-key
# ADMIN_USERNAME=your-admin-username
# ADMIN_PASSWORD=your-secure-password
# APP_DOMAIN=your-domain.com
# Run with Gunicorn
gunicorn -c gunicorn.conf.py main:app
Console output in production:
Admin user initialized: your-admin-username
Default password: your-secure-password
[2025-07-16 17:27:27 +0000] [1] [INFO] Starting gunicorn 21.2.0
[2025-07-16 17:27:27 +0000] [1] [INFO] Listening at: http://0.0.0.0:5000 (1)
[2025-07-16 17:27:27 +0000] [1] [INFO] Using worker: sync
[2025-07-16 17:27:27 +0000] [7] [INFO] Booting worker with pid: 7
[2025-07-16 17:27:27 +0000] [8] [INFO] Booting worker with pid: 8
[2025-07-16 17:27:27 +0000] [9] [INFO] Booting worker with pid: 9
[2025-07-16 17:27:27 +0000] [10] [INFO] Booting worker with pid: 10
🔧 Environment Configuration
Create a .env file in the project root with your configuration:
For Development:
# Development settings
FLASK_ENV=development
SECRET_KEY=dev-secret-key
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123
APP_DOMAIN=localhost:5000
For Production:
# Production settings (copy from .env.production and customize)
FLASK_ENV=production
SECRET_KEY=your-super-secret-key-change-this
ADMIN_USERNAME=your-admin-username
ADMIN_PASSWORD=your-secure-password
APP_DOMAIN=your-domain.com
# Security settings
SESSION_COOKIE_SECURE=true # Set to true for HTTPS
SESSION_COOKIE_HTTPONLY=true
SESSION_COOKIE_SAMESITE=Lax
# Performance settings
UPLOAD_MAX_SIZE=10485760 # 10MB
CACHE_TIMEOUT=3600 # 1 hour
🛡️ Security Considerations
Development Mode:
- ⚠️ Never use in production
- Default credentials are visible
- Debug information exposed
- Single-threaded server
Production Mode:
- ✅ Use Gunicorn WSGI server
- ✅ Change default credentials
- ✅ Use strong SECRET_KEY
- ✅ Enable HTTPS when possible
- ✅ Set secure cookie flags
- ✅ Multiple worker processes
📊 Performance Comparison
| Feature | Development | Production |
|---|---|---|
| Server | Flask dev server | Gunicorn (4 workers) |
| Performance | Basic | Optimized |
| Concurrency | Single-threaded | Multi-worker |
| Auto-reload | Yes | No |
| Debug info | Full | Minimal |
| Error handling | Verbose | Secure |
| Session security | Basic | Enhanced |
<EFBFBD>🔐 Authentication
- Default Credentials: admin / admin123
- Environment Variables:
ADMIN_USERNAME: Set custom admin usernameADMIN_PASSWORD: Set custom admin passwordSECRET_KEY: Set Flask secret key for sessions
🐳 Docker Deployment
The application is fully containerized with Docker:
- Build and run:
docker-compose up -d - View logs:
docker-compose logs -f - Stop:
docker-compose down - Full rebuild:
docker-compose up --build -d
Production Configuration
-
Set environment variables in .env:
FLASK_ENV=production SECRET_KEY=your-super-secret-key-here ADMIN_USERNAME=your-admin-username ADMIN_PASSWORD=your-secure-password APP_DOMAIN=[your-domain] # Your custom domain for URL shortener -
Deploy:
docker-compose up -d
URL Shortener Configuration
The URL shortener feature uses the APP_DOMAIN environment variable to generate short URLs:
- Development:
APP_DOMAIN=localhost:5000 - Production:
APP_DOMAIN=[your-domain]orAPP_DOMAIN=https://[your-domain]
Short URLs will be available at: https://[your-domain]/s/[short-code]
🌐 Reverse Proxy Configuration (Nginx)
When deploying behind a reverse proxy like Nginx Proxy Manager or standard Nginx, configure the proxy to route HTTPS traffic to HTTP backend:
⚠️ Important Proxy Configuration
- Frontend (Public): HTTPS (Port 443)
- Backend (Docker): HTTP (Port 8066)
- SSL Termination: At the proxy level
Nginx Proxy Manager Setup
-
Create Proxy Host:
- Domain:
[your-domain](your domain) - Forward Hostname/IP:
your-server-ip - Forward Port:
8066 - Protocol: HTTP (not HTTPS)
- Domain:
-
SSL Configuration:
- Enable SSL certificate (Let's Encrypt)
- Force SSL: Yes
- HTTP/2 Support: Yes
-
Advanced Settings (if needed):
# Custom Nginx configuration 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;
Standard Nginx Configuration
server {
listen 443 ssl http2;
server_name [your-domain];
# SSL Configuration
ssl_certificate /path/to/ssl/cert.pem;
ssl_certificate_key /path/to/ssl/private.key;
# Proxy to Docker container
location / {
proxy_pass http://localhost:8066; # Note: HTTP, not HTTPS
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name [your-domain];
return 301 https://$server_name$request_uri;
}
Common Proxy Issues & Solutions
| Issue | Cause | Solution |
|---|---|---|
| 502 Bad Gateway | HTTPS→HTTPS routing | Change backend to HTTP |
| SSL errors | Missing certificates | Configure SSL at proxy level |
| 404 on subpaths | Missing headers | Add proxy headers |
| Session issues | Domain mismatch | Set correct APP_DOMAIN |
Docker Configuration for Proxy
Ensure your docker-compose.yml exposes the correct port:
services:
qr-manager:
ports:
- "8066:5000" # Maps container port 5000 to host port 8066
environment:
- APP_DOMAIN=[your-domain] # Your public domain
📱 Usage
Generating QR Codes
- Login to the admin interface
- Select QR type: Text, URL, WiFi, Email, SMS, or vCard
- Fill in the details for your chosen type
- Customize appearance: Size, colors, style, border
- Add logo (optional): Upload custom logo for branding
- Generate and download your QR code
Dynamic Link Pages
- Create a link page from the main interface
- Add links to your collection via the edit interface
- Share the QR code that points to your link page
- Update links anytime without changing the QR code
URL Shortener
- Create shortened URLs with optional custom codes
- Generate QR codes for shortened URLs
- Track clicks and monitor usage statistics
- Redirect seamlessly from short URLs to original destinations
- Integrate with link pages by enabling shortener for individual links
Examples:
- Original:
https://very-long-domain.com/extremely/long/path/to/resource - Short:
https://[your-domain]/s/abc123
🛡️ Security Features
- Password Hashing: Uses bcrypt for secure password storage
- Session Management: Secure Flask sessions with signing
- Authentication Required: All admin functions require login
- Docker Security: Non-root user in container
- Environment Variables: Sensitive data via environment configuration
🔧 Development
Project Architecture
The application follows a modular Flask structure:
- App Factory Pattern: Clean application initialization
- Blueprint Organization: Separate route modules for different features
- Utility Modules: Reusable components for QR generation, auth, etc.
- Template Organization: Structured Jinja2 templates
- Static File Management: Organized asset storage
Adding New Features
- New Routes: Add to appropriate blueprint in
app/routes/ - New Utilities: Create modules in
app/utils/ - New Templates: Add to
app/templates/ - New Dependencies: Update
requirements.txt
📊 API Endpoints
QR Code Management
POST /api/generate- Generate QR codeGET /api/qr_codes- List all QR codesGET /api/qr_codes/{id}- Get specific QR codeDELETE /api/qr_codes/{id}- Delete QR code
Dynamic Link Pages
POST /api/create_link_page- Create dynamic link pagePOST /api/link_pages/{id}/links- Add link to pagePUT /api/link_pages/{id}/links/{link_id}- Update linkDELETE /api/link_pages/{id}/links/{link_id}- Delete link
URL Shortener
POST /api/shorten- Create standalone short URLPOST /api/generate_shortened_qr- Generate QR code with short URLGET /api/short_urls- List all short URLsGET /api/short_urls/{code}/stats- Get short URL statisticsGET /s/{code}- Redirect short URL to originalPOST /api/link_pages/{id}/links- Add link to pagePUT /api/link_pages/{id}/links/{link_id}- Update linkDELETE /api/link_pages/{id}/links/{link_id}- Delete link
🚨 Troubleshooting
Common Issues
- Permission Denied: Ensure Docker has proper permissions
- Port 5000 in use: Change port in docker-compose.yml
- Authentication Failed: Check admin credentials in .env
- Image Generation Failed: Verify PIL/Pillow installation
Health Check
Visit /health to check application status:
curl http://localhost:5000/health
📝 License
This project is licensed under the MIT License - see the LICENSE file for details.
💾 Backup & Restore System
The QR Code Manager includes a comprehensive backup system for data protection and migration.
Quick Start
Create Backup:
- Via Web: Navigate to backup management page → "Create Backup"
- Via API:
curl -X POST http://localhost:8066/api/backup/create - Via CLI:
python backup.pyor./docker_backup.sh
Manage Backups:
- List: View all backups with timestamps and sizes
- Download: Get backup files directly from web interface
- Delete: Remove individual backups with confirmation
- Cleanup: Bulk remove backups older than 7 days
What Gets Backed Up
Each backup includes:
- ✅ All QR code data and metadata
- ✅ Short URL database
- ✅ Dynamic link page configurations
- ✅ Generated QR code images
- ✅ Application settings
Restore Process
# 1. Stop application
docker compose down
# 2. Extract backup to data directory
cd data/
unzip ../backups/backup_20250801_143022.zip
# 3. Restart application
docker compose up -d
Automated Backups
Daily Backup (2 AM):
0 2 * * * cd /opt/qr-code_manager && ./docker_backup.sh
Weekly Cleanup:
0 3 * * 0 curl -X POST http://localhost:8066/api/backup/cleanup
📖 Detailed Documentation: See BACKUP_SYSTEM.md for complete backup system documentation.
🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
🧹 Data Cleanup for Deployment
When preparing for a fresh deployment or when you need to clear all data, use the provided cleanup scripts:
Option 1: Python Script (Recommended)
python clean_data.py
Option 2: Shell Script (Quick)
./clean_data.sh
What Gets Cleaned
Both scripts will remove:
- All QR codes and their data - Clears the QR codes database and deletes all generated PNG images
- All dynamic link pages - Removes all link collections and their settings
- All short URLs - Clears the URL shortener database
- All Flask sessions - Removes user session files
- All log files - Deletes any application log files
- Python cache files - Removes
__pycache__directories and.pycfiles
Safety Features
- Confirmation prompt - Both scripts require typing 'YES' to confirm the action
- Directory preservation - Required directories are recreated after cleanup
- Error handling - Scripts handle missing files/directories gracefully
Post-Cleanup Steps
After running the cleanup script:
- Start the application:
python main.py - Login with default credentials:
admin/admin123 - Important: Change the default admin password immediately
- Begin creating your QR codes and link pages
Use Cases
- Fresh deployment - Clean slate for production deployment
- Development reset - Clear test data during development
- Data migration - Prepare for moving to a new system
- Security cleanup - Remove all data when decommissioning
📞 Support
For support, please open an issue on GitHub or contact the development team.
Made with ❤️ for easy QR code management