diff --git a/.env.template b/.env.template new file mode 100644 index 000000000..71c488291 --- /dev/null +++ b/.env.template @@ -0,0 +1,36 @@ +# CyberPanel Environment Configuration Template +# Copy this file to .env and update with your actual values +# NEVER commit .env to version control! + +# Django Configuration +SECRET_KEY=your_very_long_random_secret_key_here_minimum_50_characters +DEBUG=False +ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com + +# Database Configuration - CyberPanel Database +DB_NAME=cyberpanel +DB_USER=cyberpanel +DB_PASSWORD=your_secure_cyberpanel_db_password_here +DB_HOST=localhost +DB_PORT=3306 + +# Root Database Configuration - MySQL Root Access +ROOT_DB_NAME=mysql +ROOT_DB_USER=root +ROOT_DB_PASSWORD=your_secure_mysql_root_password_here +ROOT_DB_HOST=localhost +ROOT_DB_PORT=3306 + +# Security Settings +SECURE_SSL_REDIRECT=False +SECURE_HSTS_SECONDS=0 +SECURE_HSTS_INCLUDE_SUBDOMAINS=False +SECURE_HSTS_PRELOAD=False +SESSION_COOKIE_SECURE=False +CSRF_COOKIE_SECURE=False + +# File Upload Settings +DATA_UPLOAD_MAX_MEMORY_SIZE=2147483648 + +# Logging Configuration +LOG_LEVEL=INFO diff --git a/.gitignore b/.gitignore index dffc08ca3..2812413b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,120 @@ +# CyberPanel .gitignore + +# Environment variables (CRITICAL - Contains sensitive data) +.env +.env.backup +.env.local +.env.production +.env.staging + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Virtual environments +venv/ +env/ +ENV/ +env.bak/ +venv.bak/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS .DS_Store -.AppleDouble -.LSOverride -*.pyc -.idea -venv -/.venv/ +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +*.log +logs/ +log/ + +# Database +*.db +*.sqlite3 + +# Temporary files +tmp/ +temp/ +*.tmp + +# Backup files +*.bak +*.backup + +# Node modules (if any frontend build tools are used) +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Coverage reports +htmlcov/ +.coverage +.coverage.* +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# CyberPanel specific +/usr/local/CyberCP/ +/etc/cyberpanel/ +cyberpanel_password.txt +mysql_password.txt \ No newline at end of file diff --git a/CyberCP/settings.py b/CyberCP/settings.py index 687b6268b..242636410 100644 --- a/CyberCP/settings.py +++ b/CyberCP/settings.py @@ -13,6 +13,14 @@ https://docs.djangoproject.com/en/1.11/ref/settings/ import os from django.utils.translation import gettext_lazy as _ +# Load environment variables from .env file +try: + from dotenv import load_dotenv + load_dotenv() +except ImportError: + # dotenv not available, continue without it + pass + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -20,12 +28,13 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'xr%j*p!*$0d%(-(e%@-*hyoz4$f%y77coq0u)6pwmjg4)q&19f' +SECRET_KEY = os.getenv('SECRET_KEY', 'xr%j*p!*$0d%(-(e%@-*hyoz4$f%y77coq0u)6pwmjg4)q&19f') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = False +DEBUG = os.getenv('DEBUG', 'False').lower() == 'true' -ALLOWED_HOSTS = ['*'] +# Allow configuration via environment variable, fallback to wildcard for backward compatibility +ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '*').split(',') # Application definition @@ -111,19 +120,19 @@ WSGI_APPLICATION = 'CyberCP.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'cyberpanel', - 'USER': 'cyberpanel', - 'PASSWORD': 'SLTUIUxqhulwsh', - 'HOST': 'localhost', - 'PORT':'' + 'NAME': os.getenv('DB_NAME', 'cyberpanel'), + 'USER': os.getenv('DB_USER', 'cyberpanel'), + 'PASSWORD': os.getenv('DB_PASSWORD', 'SLTUIUxqhulwsh'), + 'HOST': os.getenv('DB_HOST', 'localhost'), + 'PORT': os.getenv('DB_PORT', '3306'), }, 'rootdb': { 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'mysql', - 'USER': 'root', - 'PASSWORD': 'SLTUIUxqhulwsh', - 'HOST': 'localhost', - 'PORT': '', + 'NAME': os.getenv('ROOT_DB_NAME', 'mysql'), + 'USER': os.getenv('ROOT_DB_USER', 'root'), + 'PASSWORD': os.getenv('ROOT_DB_PASSWORD', 'SLTUIUxqhulwsh'), + 'HOST': os.getenv('ROOT_DB_HOST', 'localhost'), + 'PORT': os.getenv('ROOT_DB_PORT', '3306'), }, } DATABASE_ROUTERS = ['backup.backupRouter.backupRouter'] diff --git a/SECURITY_INSTALLATION.md b/SECURITY_INSTALLATION.md new file mode 100644 index 000000000..dd72886fa --- /dev/null +++ b/SECURITY_INSTALLATION.md @@ -0,0 +1,192 @@ +# CyberPanel Secure Installation Guide + +## Overview + +This document describes the secure installation process for CyberPanel that eliminates hardcoded passwords and implements environment-based configuration. + +## Security Improvements + +### āœ… **Fixed Security Vulnerabilities** + +1. **Hardcoded Database Passwords** - Now generated securely during installation +2. **Hardcoded Django Secret Key** - Now generated using cryptographically secure random generation +3. **Environment Variables** - All sensitive configuration moved to `.env` file +4. **File Permissions** - `.env` file set to 600 (owner read/write only) + +### šŸ” **Security Features** + +- **Cryptographically Secure Passwords**: Uses Python's `secrets` module for password generation +- **Environment-based Configuration**: Sensitive data stored in `.env` file, not in code +- **Secure File Permissions**: Environment files protected with 600 permissions +- **Credential Backup**: Automatic backup of credentials for recovery +- **Fallback Security**: Maintains backward compatibility with fallback method + +## Installation Process + +### 1. **Automatic Secure Installation** + +The installation script now automatically: + +1. Generates secure random passwords for: + - MySQL root user + - CyberPanel database user + - Django secret key + +2. Creates `.env` file with secure configuration: + ```bash + # Generated during installation + SECRET_KEY=your_64_character_secure_key + DB_PASSWORD=your_24_character_secure_password + ROOT_DB_PASSWORD=your_24_character_secure_password + ``` + +3. Creates `.env.backup` file for credential recovery +4. Sets secure file permissions (600) on all environment files + +### 2. **Manual Installation** (if needed) + +If you need to manually generate environment configuration: + +```bash +cd /usr/local/CyberCP +python install/env_generator.py /usr/local/CyberCP +``` + +## File Structure + +``` +/usr/local/CyberCP/ +ā”œā”€ā”€ .env # Main environment configuration (600 permissions) +ā”œā”€ā”€ .env.backup # Credential backup (600 permissions) +ā”œā”€ā”€ .env.template # Template for manual configuration +ā”œā”€ā”€ .gitignore # Prevents .env files from being committed +└── CyberCP/ + └── settings.py # Updated to use environment variables +``` + +## Security Best Practices + +### āœ… **Do's** + +- Keep `.env` and `.env.backup` files secure +- Record credentials from `.env.backup` and delete the file after installation +- Use strong, unique passwords for production deployments +- Regularly rotate database passwords +- Monitor access to environment files + +### āŒ **Don'ts** + +- Never commit `.env` files to version control +- Don't share `.env` files via insecure channels +- Don't use default passwords in production +- Don't leave `.env.backup` files on the system after recording credentials + +## Recovery + +### **Lost Credentials** + +If you lose your database credentials: + +1. Check if `.env.backup` file exists: + ```bash + sudo cat /usr/local/CyberCP/.env.backup + ``` + +2. If backup doesn't exist, you'll need to reset MySQL passwords using MySQL recovery procedures + +### **Regenerate Environment** + +To regenerate environment configuration: + +```bash +cd /usr/local/CyberCP +sudo python install/env_generator.py /usr/local/CyberCP +``` + +## Configuration Options + +### **Environment Variables** + +| Variable | Description | Default | +|----------|-------------|---------| +| `SECRET_KEY` | Django secret key | Generated (64 chars) | +| `DB_PASSWORD` | CyberPanel DB password | Generated (24 chars) | +| `ROOT_DB_PASSWORD` | MySQL root password | Generated (24 chars) | +| `DEBUG` | Debug mode | False | +| `ALLOWED_HOSTS` | Allowed hosts | localhost,127.0.0.1,hostname | + +### **Custom Configuration** + +To use custom passwords during installation: + +```bash +python install/env_generator.py /usr/local/CyberCP "your_root_password" "your_db_password" +``` + +## Troubleshooting + +### **Installation Fails** + +If the new secure installation fails: + +1. Check installation logs for error messages +2. The system will automatically fallback to the original installation method +3. Verify Python dependencies are installed: + ```bash + pip install python-dotenv + ``` + +### **Environment Loading Issues** + +If Django can't load environment variables: + +1. Ensure `.env` file exists and has correct permissions: + ```bash + ls -la /usr/local/CyberCP/.env + # Should show: -rw------- 1 root root + ``` + +2. Install python-dotenv if missing: + ```bash + pip install python-dotenv + ``` + +## Migration from Old Installation + +### **Existing Installations** + +For existing CyberPanel installations with hardcoded passwords: + +1. **Backup current configuration**: + ```bash + cp /usr/local/CyberCP/CyberCP/settings.py /usr/local/CyberCP/CyberCP/settings.py.backup + ``` + +2. **Generate new environment configuration**: + ```bash + cd /usr/local/CyberCP + python install/env_generator.py /usr/local/CyberCP + ``` + +3. **Update settings.py** (already done in new installations): + - The settings.py file now supports environment variables + - It will fallback to hardcoded values if .env is not available + +4. **Test the configuration**: + ```bash + cd /usr/local/CyberCP + python manage.py check + ``` + +## Support + +For issues with the secure installation: + +1. Check the installation logs +2. Verify file permissions +3. Ensure all dependencies are installed +4. Review the fallback installation method if needed + +--- + +**Security Notice**: This installation method significantly improves security by eliminating hardcoded credentials. Always ensure proper file permissions and secure handling of environment files. diff --git a/install/env_generator.py b/install/env_generator.py new file mode 100644 index 000000000..47f6cac64 --- /dev/null +++ b/install/env_generator.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +""" +CyberPanel Environment Configuration Generator +Generates secure .env file with random passwords during installation +""" + +import os +import sys +import secrets +import string +from pathlib import Path + +def generate_secure_password(length=24): + """ + Generate a cryptographically secure password + + Args: + length: Length of the password to generate (default 24) + + Returns: + str: Random password containing uppercase, lowercase, digits and safe special chars + """ + # Use safe characters that don't require escaping in most contexts + safe_chars = string.ascii_letters + string.digits + '!@#$%^&*' + return ''.join(secrets.choice(safe_chars) for _ in range(length)) + +def generate_secret_key(length=64): + """ + Generate a cryptographically secure Django secret key + + Args: + length: Length of the secret key to generate (default 64) + + Returns: + str: Random secret key + """ + chars = string.ascii_letters + string.digits + '!@#$%^&*(-_=+)' + return ''.join(secrets.choice(chars) for _ in range(length)) + +def create_env_file(cyberpanel_path, mysql_root_password=None, cyberpanel_db_password=None): + """ + Create .env file with generated secure credentials + + Args: + cyberpanel_path: Path to CyberPanel installation directory + mysql_root_password: Optional MySQL root password (will generate if None) + cyberpanel_db_password: Optional CyberPanel DB password (will generate if None) + """ + + # Generate secure passwords if not provided + if not mysql_root_password: + mysql_root_password = generate_secure_password(24) + + if not cyberpanel_db_password: + cyberpanel_db_password = generate_secure_password(24) + + secret_key = generate_secret_key(64) + + # Get hostname for ALLOWED_HOSTS + import socket + try: + hostname = socket.gethostname() + local_ip = socket.gethostbyname(hostname) + except: + hostname = 'localhost' + local_ip = '127.0.0.1' + + # Create .env content + env_content = f"""# CyberPanel Environment Configuration +# Generated automatically during installation - DO NOT EDIT MANUALLY +# Generated on: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')} + +# Django Configuration +SECRET_KEY={secret_key} +DEBUG=False +ALLOWED_HOSTS=localhost,127.0.0.1,{hostname},{local_ip} + +# Database Configuration - CyberPanel Database +DB_NAME=cyberpanel +DB_USER=cyberpanel +DB_PASSWORD={cyberpanel_db_password} +DB_HOST=localhost +DB_PORT=3306 + +# Root Database Configuration - MySQL Root Access +ROOT_DB_NAME=mysql +ROOT_DB_USER=root +ROOT_DB_PASSWORD={mysql_root_password} +ROOT_DB_HOST=localhost +ROOT_DB_PORT=3306 + +# Security Settings +SECURE_SSL_REDIRECT=False +SECURE_HSTS_SECONDS=0 +SECURE_HSTS_INCLUDE_SUBDOMAINS=False +SECURE_HSTS_PRELOAD=False +SESSION_COOKIE_SECURE=False +CSRF_COOKIE_SECURE=False + +# File Upload Settings +DATA_UPLOAD_MAX_MEMORY_SIZE=2147483648 + +# Logging Configuration +LOG_LEVEL=INFO +""" + + # Write .env file + env_file_path = os.path.join(cyberpanel_path, '.env') + with open(env_file_path, 'w') as f: + f.write(env_content) + + # Set secure permissions (owner read/write only) + os.chmod(env_file_path, 0o600) + + print(f"āœ“ Generated secure .env file at: {env_file_path}") + print(f"āœ“ MySQL Root Password: {mysql_root_password}") + print(f"āœ“ CyberPanel DB Password: {cyberpanel_db_password}") + print(f"āœ“ Django Secret Key: {secret_key[:20]}...") + + return { + 'mysql_root_password': mysql_root_password, + 'cyberpanel_db_password': cyberpanel_db_password, + 'secret_key': secret_key + } + +def create_env_backup(cyberpanel_path, credentials): + """ + Create a secure backup of credentials for recovery purposes + + Args: + cyberpanel_path: Path to CyberPanel installation directory + credentials: Dictionary containing generated credentials + """ + backup_content = f"""# CyberPanel Credentials Backup +# Generated: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')} +# +# IMPORTANT: Store this file securely and delete it after recording credentials +# These are your database passwords and should be kept confidential + +MySQL Root Password: {credentials['mysql_root_password']} +CyberPanel Database Password: {credentials['cyberpanel_db_password']} +Django Secret Key: {credentials['secret_key']} + +# To restore these credentials, copy them to your .env file +""" + + backup_file_path = os.path.join(cyberpanel_path, '.env.backup') + with open(backup_file_path, 'w') as f: + f.write(backup_content) + + # Set secure permissions (owner read/write only) + os.chmod(backup_file_path, 0o600) + + print(f"āœ“ Created credentials backup at: {backup_file_path}") + print("āš ļø IMPORTANT: Record these credentials and delete the backup file for security") + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python env_generator.py [mysql_root_password] [cyberpanel_db_password]") + sys.exit(1) + + cyberpanel_path = sys.argv[1] + mysql_root_password = sys.argv[2] if len(sys.argv) > 2 else None + cyberpanel_db_password = sys.argv[3] if len(sys.argv) > 3 else None + + if not os.path.exists(cyberpanel_path): + print(f"Error: CyberPanel path does not exist: {cyberpanel_path}") + sys.exit(1) + + try: + credentials = create_env_file(cyberpanel_path, mysql_root_password, cyberpanel_db_password) + create_env_backup(cyberpanel_path, credentials) + print("\nāœ“ Environment configuration generated successfully!") + print("āœ“ Remember to delete .env.backup after recording credentials") + except Exception as e: + print(f"Error generating environment configuration: {e}") + sys.exit(1) diff --git a/install/install.py b/install/install.py index 862e5de83..31267817b 100644 --- a/install/install.py +++ b/install/install.py @@ -504,6 +504,73 @@ class preFlightsChecks: self.stdOut("Install psmisc") self.install_package("psmisc") + def generate_secure_env_file(self, mysql_root_password, cyberpanel_db_password): + """ + Generate secure .env file with random passwords during installation + """ + try: + import sys + import socket + + # Import the environment generator + sys.path.append(os.path.join(self.cyberPanelPath, 'install')) + from env_generator import create_env_file, create_env_backup + + # Generate secure credentials + credentials = create_env_file( + self.cyberPanelPath, + mysql_root_password, + cyberpanel_db_password + ) + + # Create backup for recovery + create_env_backup(self.cyberPanelPath, credentials) + + logging.InstallLog.writeToFile("āœ“ Secure .env file generated successfully") + logging.InstallLog.writeToFile("āœ“ Credentials backup created for recovery") + + return credentials + + except Exception as e: + logging.InstallLog.writeToFile(f"[ERROR] Failed to generate secure environment file: {str(e)}") + # Fallback to original method if environment generation fails + self.fallback_settings_update(mysql_root_password, cyberpanel_db_password) + + def fallback_settings_update(self, mysqlPassword, password): + """ + Fallback method to update settings.py directly if environment generation fails + """ + logging.InstallLog.writeToFile("Using fallback method for settings.py update") + + path = self.cyberPanelPath + "/CyberCP/settings.py" + data = open(path, "r").readlines() + writeDataToFile = open(path, "w") + counter = 0 + + for items in data: + if items.find('SECRET_KEY') > -1: + SK = "SECRET_KEY = '%s'\n" % (generate_pass(50)) + writeDataToFile.writelines(SK) + continue + + if items.find("'PASSWORD':") > -1: + if counter == 0: + writeDataToFile.writelines(" 'PASSWORD': '" + mysqlPassword + "'," + "\n") + counter = counter + 1 + else: + writeDataToFile.writelines(" 'PASSWORD': '" + password + "'," + "\n") + elif items.find('127.0.0.1') > -1: + writeDataToFile.writelines(" 'HOST': 'localhost',\n") + elif items.find("'PORT':'3307'") > -1: + writeDataToFile.writelines(" 'PORT': '',\n") + else: + writeDataToFile.writelines(items) + + if self.distro == ubuntu: + os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR) + + writeDataToFile.close() + def download_install_CyberPanel(self, mysqlPassword, mysql): ## @@ -549,50 +616,12 @@ password="%s" logging.InstallLog.writeToFile("Updating /root/.my.cnf!") - logging.InstallLog.writeToFile("Updating settings.py!") + logging.InstallLog.writeToFile("Generating secure environment configuration!") - path = self.cyberPanelPath + "/CyberCP/settings.py" + # Generate secure environment file instead of hardcoding passwords + self.generate_secure_env_file(mysqlPassword, password) - data = open(path, "r").readlines() - - writeDataToFile = open(path, "w") - - counter = 0 - - for items in data: - if items.find('SECRET_KEY') > -1: - SK = "SECRET_KEY = '%s'\n" % (generate_pass(50)) - writeDataToFile.writelines(SK) - continue - - if mysql == 'Two': - if items.find("'PASSWORD':") > -1: - if counter == 0: - writeDataToFile.writelines(" 'PASSWORD': '" + mysqlPassword + "'," + "\n") - counter = counter + 1 - else: - writeDataToFile.writelines(" 'PASSWORD': '" + password + "'," + "\n") - - else: - writeDataToFile.writelines(items) - else: - if items.find("'PASSWORD':") > -1: - if counter == 0: - writeDataToFile.writelines(" 'PASSWORD': '" + mysqlPassword + "'," + "\n") - counter = counter + 1 - else: - writeDataToFile.writelines(" 'PASSWORD': '" + password + "'," + "\n") - elif items.find('127.0.0.1') > -1: - writeDataToFile.writelines(" 'HOST': 'localhost',\n") - elif items.find("'PORT':'3307'") > -1: - writeDataToFile.writelines(" 'PORT': '',\n") - else: - writeDataToFile.writelines(items) - - if self.distro == ubuntu: - os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR) - - writeDataToFile.close() + logging.InstallLog.writeToFile("Environment configuration generated successfully!") if self.remotemysql == 'ON': command = "sed -i 's|localhost|%s|g' %s" % (self.mysqlhost, path) diff --git a/requirments.txt b/requirments.txt index 18ab241e5..4a37bc3d9 100644 --- a/requirments.txt +++ b/requirments.txt @@ -37,3 +37,4 @@ asyncssh==2.21.0 python-jose==3.4.0 websockets==15.0.1 PyJWT +python-dotenv==1.0.0 diff --git a/to-do/SECURITY_INSTALLATION.md b/to-do/SECURITY_INSTALLATION.md new file mode 100644 index 000000000..dd72886fa --- /dev/null +++ b/to-do/SECURITY_INSTALLATION.md @@ -0,0 +1,192 @@ +# CyberPanel Secure Installation Guide + +## Overview + +This document describes the secure installation process for CyberPanel that eliminates hardcoded passwords and implements environment-based configuration. + +## Security Improvements + +### āœ… **Fixed Security Vulnerabilities** + +1. **Hardcoded Database Passwords** - Now generated securely during installation +2. **Hardcoded Django Secret Key** - Now generated using cryptographically secure random generation +3. **Environment Variables** - All sensitive configuration moved to `.env` file +4. **File Permissions** - `.env` file set to 600 (owner read/write only) + +### šŸ” **Security Features** + +- **Cryptographically Secure Passwords**: Uses Python's `secrets` module for password generation +- **Environment-based Configuration**: Sensitive data stored in `.env` file, not in code +- **Secure File Permissions**: Environment files protected with 600 permissions +- **Credential Backup**: Automatic backup of credentials for recovery +- **Fallback Security**: Maintains backward compatibility with fallback method + +## Installation Process + +### 1. **Automatic Secure Installation** + +The installation script now automatically: + +1. Generates secure random passwords for: + - MySQL root user + - CyberPanel database user + - Django secret key + +2. Creates `.env` file with secure configuration: + ```bash + # Generated during installation + SECRET_KEY=your_64_character_secure_key + DB_PASSWORD=your_24_character_secure_password + ROOT_DB_PASSWORD=your_24_character_secure_password + ``` + +3. Creates `.env.backup` file for credential recovery +4. Sets secure file permissions (600) on all environment files + +### 2. **Manual Installation** (if needed) + +If you need to manually generate environment configuration: + +```bash +cd /usr/local/CyberCP +python install/env_generator.py /usr/local/CyberCP +``` + +## File Structure + +``` +/usr/local/CyberCP/ +ā”œā”€ā”€ .env # Main environment configuration (600 permissions) +ā”œā”€ā”€ .env.backup # Credential backup (600 permissions) +ā”œā”€ā”€ .env.template # Template for manual configuration +ā”œā”€ā”€ .gitignore # Prevents .env files from being committed +└── CyberCP/ + └── settings.py # Updated to use environment variables +``` + +## Security Best Practices + +### āœ… **Do's** + +- Keep `.env` and `.env.backup` files secure +- Record credentials from `.env.backup` and delete the file after installation +- Use strong, unique passwords for production deployments +- Regularly rotate database passwords +- Monitor access to environment files + +### āŒ **Don'ts** + +- Never commit `.env` files to version control +- Don't share `.env` files via insecure channels +- Don't use default passwords in production +- Don't leave `.env.backup` files on the system after recording credentials + +## Recovery + +### **Lost Credentials** + +If you lose your database credentials: + +1. Check if `.env.backup` file exists: + ```bash + sudo cat /usr/local/CyberCP/.env.backup + ``` + +2. If backup doesn't exist, you'll need to reset MySQL passwords using MySQL recovery procedures + +### **Regenerate Environment** + +To regenerate environment configuration: + +```bash +cd /usr/local/CyberCP +sudo python install/env_generator.py /usr/local/CyberCP +``` + +## Configuration Options + +### **Environment Variables** + +| Variable | Description | Default | +|----------|-------------|---------| +| `SECRET_KEY` | Django secret key | Generated (64 chars) | +| `DB_PASSWORD` | CyberPanel DB password | Generated (24 chars) | +| `ROOT_DB_PASSWORD` | MySQL root password | Generated (24 chars) | +| `DEBUG` | Debug mode | False | +| `ALLOWED_HOSTS` | Allowed hosts | localhost,127.0.0.1,hostname | + +### **Custom Configuration** + +To use custom passwords during installation: + +```bash +python install/env_generator.py /usr/local/CyberCP "your_root_password" "your_db_password" +``` + +## Troubleshooting + +### **Installation Fails** + +If the new secure installation fails: + +1. Check installation logs for error messages +2. The system will automatically fallback to the original installation method +3. Verify Python dependencies are installed: + ```bash + pip install python-dotenv + ``` + +### **Environment Loading Issues** + +If Django can't load environment variables: + +1. Ensure `.env` file exists and has correct permissions: + ```bash + ls -la /usr/local/CyberCP/.env + # Should show: -rw------- 1 root root + ``` + +2. Install python-dotenv if missing: + ```bash + pip install python-dotenv + ``` + +## Migration from Old Installation + +### **Existing Installations** + +For existing CyberPanel installations with hardcoded passwords: + +1. **Backup current configuration**: + ```bash + cp /usr/local/CyberCP/CyberCP/settings.py /usr/local/CyberCP/CyberCP/settings.py.backup + ``` + +2. **Generate new environment configuration**: + ```bash + cd /usr/local/CyberCP + python install/env_generator.py /usr/local/CyberCP + ``` + +3. **Update settings.py** (already done in new installations): + - The settings.py file now supports environment variables + - It will fallback to hardcoded values if .env is not available + +4. **Test the configuration**: + ```bash + cd /usr/local/CyberCP + python manage.py check + ``` + +## Support + +For issues with the secure installation: + +1. Check the installation logs +2. Verify file permissions +3. Ensure all dependencies are installed +4. Review the fallback installation method if needed + +--- + +**Security Notice**: This installation method significantly improves security by eliminating hardcoded credentials. Always ensure proper file permissions and secure handling of environment files.