⚠️ Documentation Under Review: This documentation is currently being updated and verified against the actual implementation. Some information may be incorrect or incomplete. Please verify all code examples against the actual source code before use.
The Neuron CMS uses YAML configuration files located in the config/ directory. Configuration is managed through the SettingManager component and can be accessed at runtime.
The CMS uses a hierarchical configuration structure supporting environment-specific overrides and encrypted secrets:
config/neuron.yaml - Main application configurationconfig/routing.yaml - URL rewrites and controller pathsconfig/auth.yaml - Authentication and member settingsconfig/event-listeners.yaml - Event listener mappingsconfig/services.yaml - Dependency injection container servicesconfig/environments/{env}.yaml - Environment-specific config overrides (e.g., local.yaml, production.yaml)config/master.key - Base secrets encryption key (gitignored)config/secrets.yml.enc - Encrypted base secrets (committed)config/environments/{env}.key - Environment secrets encryption key (gitignored)config/environments/{env}.secrets.yml.enc - Encrypted environment secrets (committed)Note: The neuron.yaml file is created during installation via php neuron cms:install from the template at vendor/neuron-php/cms/resources/config/neuron.yaml.example.
Primary application configuration file containing system, logging, caching, views, site, theme, database, and email settings.
Controls system-level behavior and paths.
system:
timezone: UTC # PHP timezone identifier
base_path: resources # Base path for resources (relative or absolute)
routes_path: resources/config # Path to route configuration files
Options:
timezone: PHP timezone identifier (see PHP timezones). Default: UTCbase_path: Base directory for resources (views, config, assets). Default: resourcesroutes_path: Directory containing route definition files. Default: resources/configDefines controller paths for autoloading.
routing:
controller_paths:
- path: 'vendor/neuron-php/cms/src/Cms/Controllers'
namespace: 'Neuron\Cms\Controllers'
Options:
controller_paths: Array of paths and namespaces for controller autoloading
path: Directory containing controllersnamespace: PHP namespace for controllers in that pathControls application logging behavior.
logging:
destination: \Neuron\Log\Destination\File # Log destination class
format: \Neuron\Log\Format\PlainText # Log format class
file: storage/logs/app.log # Log file path
level: info # Minimum log level
Available Destinations:
\Neuron\Log\Destination\File - File-based logging\Neuron\Log\Destination\SysLog - System log\Neuron\Log\Destination\StdOut - Standard output\Neuron\Log\Destination\StdErr - Standard error\Neuron\Log\Destination\StdOutStdErr - Both stdout and stderr\Neuron\Log\Destination\DevNull - Discard logs\Neuron\Log\Destination\Email - Email logs\Neuron\Log\Destination\Slack - Slack integration\Neuron\Log\Destination\WebHookPost - Webhook endpoint\Neuron\Log\Destination\Socket - Socket connection\Neuron\Log\Destination\WebSocket - WebSocket connection\Neuron\Log\Destination\Nightwatch - Nightwatch service\Neuron\Log\Destination\Papertrail - Papertrail service\Neuron\Log\Destination\Sqs - AWS SQS\Neuron\Log\Destination\Memory - In-memory (for testing)Available Formats:
\Neuron\Log\Format\PlainText - Human-readable text\Neuron\Log\Format\JSON - JSON format\Neuron\Log\Format\CSV - CSV format\Neuron\Log\Format\HTML - HTML format\Neuron\Log\Format\HTMLEmail - HTML email format\Neuron\Log\Format\Raw - Raw unformatted\Neuron\Log\Format\Slack - Slack-formatted\Neuron\Log\Format\Nightwatch - Nightwatch formatOptions:
destination: Fully qualified class name implementing log destinationformat: Fully qualified class name implementing log formatfile: Path to log file (relative to project root). Only for File destination. Default: storage/logs/app.loglevel: Minimum log level. Options: debug, info, warning, errorControls view and content caching.
cache:
enabled: false # Enable caching
storage: file # Storage driver
path: storage/cache/views # Cache directory
ttl: 3600 # Time-to-live in seconds
html: true # Cache HTML output
markdown: true # Cache markdown rendering
json: false # Cache JSON output
xml: false # Cache XML output
Options:
enabled: Enable or disable caching system. Default: falsestorage: Cache storage driver. Currently supports: filepath: Directory for cache files. Default: storage/cache/viewsttl: Default time-to-live in seconds. Default: 3600 (1 hour)html: Cache rendered HTML views. Default: truemarkdown: Cache rendered markdown content. Default: truejson: Cache JSON responses. Default: falsexml: Cache XML responses. Default: falseControls view template location.
views:
path: resources/views # Path to view templates
Options:
path: Directory containing view templates. Default: resources/viewsSite metadata and branding.
site:
name: 'Neuron CMS' # Site name
url: 'https://localhost' # Base URL
description: 'A modern content management system built with Neuron.'
title: 'Neuron CMS' # Default page title
Options:
name: Site name displayed throughout the applicationurl: Base URL for the site (include protocol, no trailing slash)description: Site description for meta tags and SEOtitle: Default page titleBootswatch theme selection for different user roles.
theme:
admin: vapor # Admin portal theme (for admin role users)
subscriber: sandstone # Member portal theme (for subscriber, editor, author roles)
guest: sandstone # Guest theme (for public website and login/registration)
Available Themes:
cerulean, cosmo, cyborg, darkly, flatly, journal, litera, lumen, lux, materia, minty, morph, pulse, quartz, sandstone, simplex, sketchy, slate, solar, spacelab, superhero, united, vapor, yeti, zephyr
View themes at bootswatch.com
Database connection settings supporting SQLite, MySQL, and PostgreSQL.
# SQLite
database:
adapter: sqlite
name: storage/database.sqlite3
# MySQL/MariaDB
database:
adapter: mysql
host: localhost
port: 3306
name: cms_database
user: cms_user
pass: secure_password
charset: utf8mb4
# PostgreSQL
database:
adapter: pgsql
host: localhost
port: 5432
name: cms_database
user: cms_user
pass: secure_password
# URL Format (Alternative)
database:
url: mysql://user:pass@localhost:3306/dbname?charset=utf8mb4
# or
url: postgresql://user:pass@localhost:5432/dbname
# or
url: sqlite:///storage/database.sqlite3
Options:
adapter: Database adapter (sqlite, mysql, pgsql)name: Database name or file path (SQLite)host: Database server hostname (MySQL/PostgreSQL)port: Database server port (MySQL: 3306, PostgreSQL: 5432)user: Database username (MySQL/PostgreSQL)pass: Database password (MySQL/PostgreSQL)charset: Character encoding (MySQL only, default: utf8mb4)url: Alternative URL-based configurationDatabase migration and schema export settings.
migrations:
path: db/migrate # Migration files directory
seeds_path: db/seed # Seed files directory
table: phinx_log # Migration tracking table
schema_file: db/schema.yaml # Schema export file path
auto_dump_schema: false # Auto-export schema after migrations
Options:
path: Directory for migration files. Default: db/migrateseeds_path: Directory for seed files. Default: db/seedtable: Database table for tracking migrations. Default: phinx_logschema_file: Path for schema export file. Default: db/schema.yamlauto_dump_schema: Auto-export schema after migrations. Default: falseEmail delivery configuration using PHPMailer.
email:
driver: smtp # Transport driver
host: smtp.gmail.com # SMTP server hostname
port: 587 # SMTP server port
username: [email protected] # SMTP username
password: your-app-password # SMTP password
encryption: tls # Encryption method
from_address: [email protected] # Default from address
from_name: My Website # Default from name
test_mode: false # Log emails instead of sending
Driver Options: smtp, sendmail, mail
SMTP Options:
host: SMTP server hostnameport: SMTP server port (587 for TLS, 465 for SSL, 25 for unencrypted)username: SMTP authentication usernamepassword: SMTP authentication passwordencryption: tls or ssl or emptyCommon Options:
from_address: Default sender email addressfrom_name: Default sender nametest_mode: When true, emails are logged instead of sentCloud-based image management service (optional).
cloudinary:
cloud_name: your-cloud-name
api_key: your-api-key
api_secret: your-api-secret
folder: neuron-cms/images
max_file_size: 5242880
allowed_formats: [jpg, jpeg, png, gif, webp]
If not configured, image uploads will be disabled in the admin interface.
System maintenance mode settings.
maintenance:
default_message: 'Site is currently under maintenance. Please check back soon.'
allowed_ips: ['127.0.0.1', '::1']
retry_after: 3600
custom_view: null
show_countdown: false
Note: Maintenance mode is managed via CLI commands (cms:maintenance:enable/disable) rather than configuration.
Authentication and member registration configuration.
auth:
default: session # Default authentication driver
session:
lifetime: 120 # Session lifetime in minutes
expire_on_close: false # Expire session when browser closes
cookie_name: neuron_session # Session cookie name
cookie_httponly: true # Prevent JavaScript access to cookie
cookie_secure: true # Require HTTPS
cookie_samesite: Lax # CSRF protection
remember:
enabled: true # Enable "remember me" functionality
lifetime: 43200 # Remember token lifetime in minutes (30 days)
passwords:
min_length: 8 # Minimum password length
require_uppercase: true # Require uppercase letter
require_lowercase: true # Require lowercase letter
require_numbers: true # Require number
require_special_chars: false # Require special character
hash_algorithm: argon2id # Password hash algorithm
throttle:
enabled: true # Enable brute force protection
max_attempts: 5 # Maximum failed login attempts
lockout_duration: 15 # Account lockout duration in minutes
storage:
type: file # User storage type
path: storage/users # Storage path (not actively used)
member:
registration_enabled: true # Enable public registration
require_email_verification: true # Require email verification
default_role: subscriber # Default role for new members
verification_token_expiration_minutes: 60
verification_url: /verify-email
resend_throttle_seconds: 60
Note: Member settings are in auth.yaml, not neuron.yaml.
HTTP route definitions (typically in resources/config/routes.yaml).
home:
method: GET
route: /
controller: Neuron\Cms\Controllers\Home@index
admin_dashboard:
method: GET
route: /admin/dashboard
controller: Neuron\Cms\Controllers\Admin\Dashboard@index
filter: auth
Route Structure:
method: HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)route: URL path pattern (supports parameters: /posts/{id})controller: Controller class and method (ClassName@methodName)filter: Optional filters (auth, csrf, or comma-separated: auth,csrf)Event system configuration (typically in resources/config/event-listeners.yaml).
events:
user.created:
class: 'Neuron\Cms\Events\UserCreatedEvent'
listeners:
- 'Neuron\Cms\Listeners\SendWelcomeEmailListener'
- 'Neuron\Cms\Listeners\LogUserActivityListener'
Structure:
user.created)
class: Fully qualified event class namelisteners: Array of listener class names (execute in order)use Neuron\Patterns\Registry;
// Get SettingManager from Registry
$settings = Registry::getInstance()->get( 'Settings' );
// Get single value
$timezone = $settings->get( 'system', 'timezone' );
$dbAdapter = $settings->get( 'database', 'adapter' );
$sessionLifetime = $settings->get( 'auth.session', 'lifetime' );
// Get entire section
$dbConfig = $settings->getSection( 'database' );
$authConfig = $settings->getSection( 'auth' );
$memberConfig = $settings->getSection( 'member' );
// Check if setting exists
if( $settings->has( 'email', 'test_mode' ) )
{
$testMode = $settings->get( 'email', 'test_mode' );
}
From neuron.yaml:
system - System settingsrouting - Controller pathslogging - Logging configurationcache - Cache settingsviews - View pathssite - Site metadatatheme - Theme selectiondatabase - Database connectionmigrations - Migration settingsemail - Email configurationcloudinary - Image service (optional)maintenance - Maintenance modeFrom auth.yaml:
auth - Authentication settingsauth.session - Session configurationauth.remember - Remember me settingsauth.passwords - Password requirementsauth.throttle - Brute force protectionauth.storage - Storage settingsmember - Member registrationThe CMS automatically loads environment-specific configuration based on the APP_ENV environment variable.
config/
├── neuron.yaml # Base configuration
├── routing.yaml # URL rewrites and controller paths
├── auth.yaml # Authentication settings
├── event-listeners.yaml # Event system configuration
├── services.yaml # DI container services
├── master.key # Base secrets key (gitignored)
├── secrets.yml.enc # Base secrets (committed)
└── environments/
├── local.yaml # Local development config
├── local.key # Local secrets key (gitignored)
├── local.secrets.yml.enc # Local secrets (committed)
├── testing.yaml # Testing environment config
├── testing.key # Testing secrets key (gitignored)
├── testing.secrets.yml.enc # Testing secrets (committed)
├── production.yaml # Production config overrides
├── production.key # Production secrets key (gitignored)
└── production.secrets.yml.enc # Production secrets (committed)
Set the APP_ENV environment variable to determine which configuration is loaded:
Apache (.htaccess or VirtualHost):
SetEnv APP_ENV local
Docker Compose:
environment:
APP_ENV: production
Command Line:
export APP_ENV=local
php index.php
Railway/Cloud Platform:
Set APP_ENV=production in your platform's environment variables.
Configuration is loaded in the following order (later sources override earlier ones):
config/neuron.yaml - Base application configurationconfig/environments/{env}.yaml - Environment-specific overrides (e.g., local.yaml)config/secrets.yml.enc - Encrypted base secrets (shared across environments)config/environments/{env}.secrets.yml.enc - Encrypted environment-specific secretsDATABASE_URL, NEURON_MASTER_KEY)Example: If APP_ENV=local, the system loads:
neuron.yamlenvironments/local.yaml (overrides neuron.yaml values)secrets.yml.enc (if exists)environments/local.secrets.yml.enc (if exists, overrides secrets.yml.enc)config/neuron.yaml (base):
logging:
level: error
file: storage/logs/app.log
cache:
enabled: true
config/environments/local.yaml (development override):
logging:
level: debug # Override: more verbose logging in development
cache:
enabled: false # Override: disable caching for faster iteration
The local environment automatically gets debug logging and caching disabled, while production uses the base configuration.
The CMS provides a Rails-inspired encrypted secrets system for storing sensitive configuration data (API keys, passwords, tokens) securely in version control.
Benefits:
.env filesWhat Should Go in Secrets:
What Should Stay in Plain Config:
Base Secrets (config/secrets.yml.enc):
config/master.keyEnvironment-Specific Secrets (config/environments/{env}.secrets.yml.enc):
config/environments/{env}.key)Priority: Environment-specific secrets override base secrets, which override plain configuration files.
master.key (config/master.key):
php neuron secrets:key:generateNEURON_MASTER_KEY environment variableEnvironment Keys (config/environments/{env}.key):
php neuron secrets:key:generate --env={env}NEURON_{ENV}_KEY environment variableProduction Deployment: For production, store the encryption key as an environment variable instead of a file:
# Railway, Heroku, etc.
NEURON_MASTER_KEY=your-64-character-hex-key
# Or environment-specific
NEURON_PRODUCTION_KEY=your-64-character-hex-key
Create a new encryption key (32 bytes, 64 hex characters):
# Generate base master key
php neuron secrets:key:generate
# Generate environment-specific key
php neuron secrets:key:generate --env=production
php neuron secrets:key:generate --env=local
# Show the generated key (for copying to environment variables)
php neuron secrets:key:generate --show
# Force overwrite existing key
php neuron secrets:key:generate --force
Edit encrypted secrets in your default editor (set via EDITOR environment variable or defaults to vi):
# Edit base secrets
php neuron secrets:edit
# Edit environment-specific secrets
php neuron secrets:edit --env=production
php neuron secrets:edit --env=local
# Use specific editor
php neuron secrets:edit --editor=nano
php neuron secrets:edit --editor=code --wait # VS Code
Editor Opens Decrypted YAML:
# config/secrets.yml (decrypted temporarily)
database:
password: my_secure_password
stripe:
api_key: sk_test_123456789
webhook_secret: whsec_abcdefghij
smtp:
username: [email protected]
password: smtp_password_here
When you save and close the editor, the file is automatically encrypted and saved to .secrets.yml.enc.
Display decrypted secrets without editing:
# Show all base secrets
php neuron secrets:show
# Show environment-specific secrets
php neuron secrets:show --env=production
# Show a specific key
php neuron secrets:show --key=database.password
php neuron secrets:show --env=production --key=stripe.api_key
# Skip confirmation for production (dangerous!)
php neuron secrets:show --env=production --force
Security Note: The secrets:show command requires confirmation before displaying production secrets to prevent accidental exposure.
Secrets are automatically loaded into the SettingManager during bootstrap. Access them like any other configuration:
use Neuron\Patterns\Registry;
$settings = Registry::getInstance()->get( 'Settings' );
// Access secrets using dot notation
$dbPassword = $settings->get( 'database', 'password' );
$stripeKey = $settings->get( 'stripe', 'api_key' );
$smtpPassword = $settings->get( 'smtp', 'password' );
// Check if secret exists
if( $settings->has( 'stripe', 'webhook_secret' ) )
{
$webhookSecret = $settings->get( 'stripe', 'webhook_secret' );
}
Security:
.key files - Always add to .gitignoreNEURON_MASTER_KEY environment variablesecrets:show - Production secrets should require confirmationOrganization:
stripe.api_key not stripe_keyDevelopment Workflow:
secrets:key:generate before secrets:editsecrets:edit --env=local for development.secrets.yml.enc but not .key filesExample .gitignore:
# Encryption keys (NEVER commit these)
config/master.key
config/environments/*.key
# Keep encrypted secrets (safe to commit)
!config/secrets.yml.enc
!config/environments/*.secrets.yml.enc
"Encryption key not found" error:
config/master.key or config/environments/{env}.key existsNEURON_MASTER_KEY or NEURON_{ENV}_KEY environment variable"Invalid encryption key" error:
php neuron secrets:key:generate --forceSecrets not loading in application:
APP_ENV matches the secrets file name.secrets.yml.enc filesEditor doesn't open:
EDITOR environment variable: export EDITOR=nanophp neuron secrets:edit --editor=nanocookie_secure: truecsrf filter on state-changing routescache.enabled: trueerror in production, debug in developmenttest_mode: true to log emailscache.enabled: false for faster iterationlevel: debug for detailed logsCheck:
config/ directoryCheck:
database: section exists in neuron.yamlsqlite, mysql, pgsql)Check:
cookie_secure: false for HTTP developmentcookie_samesite: Lax for compatibilitycookie_secure settingCheck:
test_mode: false in production