Web Hosting Control Panel
Everything you need to know about SetModus
A web space is the core hosting unit — an isolated environment with its own system user, home directory, disk quota, and PHP-FPM pool. Think of it as a container for one or more websites.
Yes. Each web space can host multiple domains up to the limit set by its resource plan. One domain is marked as the primary domain and serves as the web space's display name.
Web spaces use a two-step safety process: first terminate (stops traffic), then delete (removes all configs, directories, and files). This prevents accidental data loss.
Suspension is reversible and takes the web space offline while preserving all data. Nginx vhosts are unlinked from sites-enabled/ so visitors get a connection refused. PHP-FPM pools are not deployed for inactive domains. All files, database data, SSL certificates, and SSH keys remain on disk — ready for reactivation.
Suspend is temporary and reversible — the web space can be reactivated with all data intact. Terminate is permanent — the web space cannot be reactivated. To fully remove a terminated web space's files, you must then delete it, which triggers cleanup of the Unix user, home directory, Nginx configs, and PHP-FPM pools.
Yes. When enabled in Settings, SetModus can auto-suspend web spaces for disk quota violations (usage ≥ 100%) and traffic quota violations (bandwidth exceeds resource plan limit). Disk-suspended web spaces auto-reactivate when usage drops below quota. Traffic-suspended web spaces require manual reactivation by an admin.
Configurable email notifications are sent to admins, clients, and/or resellers when quota warnings are triggered, when auto-suspension occurs, and when usage drops back to normal. Repeat warnings are throttled to avoid flooding (default: once per 7 days).
A client is an end customer who owns one or more web spaces. Clients have their own login portal where they can manage domains, view web space status, and request SSL certificates.
Suspension cascades: the client's active web spaces are suspended, all active domains are deactivated, and the client can no longer log in. Nginx and PHP-FPM configs are regenerated to block traffic.
Admin users have two roles: Admin (full control over all resources) and Read-Only (view everything but cannot make changes). Both roles access the admin panel.
Admin users manage the entire hosting infrastructure through the admin panel. Clients only see their own web spaces and domains through the client portal. They are separate login systems.
A reseller is a business that sells hosting services to their own clients using your infrastructure. Each reseller operates under a reseller plan that defines their limits (max clients, web spaces, domains, disk quota).
Suspension cascades through the entire hierarchy: all the reseller's active clients are suspended, their web spaces are suspended, and all active domains are deactivated. Neither the reseller nor their clients can log in.
Reseller limits are aggregate across all their clients. The "Max Domains" limit counts every domain on every web space of every client. When the limit is reached, no new domains can be created until the plan is upgraded or resources are freed.
Direct clients are managed by the platform admin and have no aggregate limits — they can create unlimited web spaces and domains (subject to per-web-space resource plan limits). Reseller clients are constrained by their reseller's plan with enforced aggregate limits on domains, web spaces, and disk usage.
Use the Reseller system for license enforcement: (1) Create a ResellerPlan for each tier (e.g., "License-100" with max_domains: 100), (2) Create a Reseller for each license sale, (3) Create a Client under that reseller. All limits are enforced automatically.
Reseller Plan defines aggregate limits → Reseller manages clients → Client owns Web Spaces → Web Space contains Domains. Resource Plans define per-web-space limits (domains, disk, PHP workers) while Reseller Plans define aggregate limits across all clients.
Activating a domain creates its Nginx virtual host configuration and PHP-FPM pool, making the site accessible on the web. Deactivating removes the configuration and takes the site offline.
Each web space has one primary domain used as its display name. The first domain added is automatically set as primary. If deleted, the next domain is promoted automatically.
No. Website files live in the web space directory, not under the domain. Deleting a domain removes its Nginx config and symlink but leaves all files intact — they belong to the web space.
Hosting plans define resource limits for a web space: disk quota, max domains, max databases, PHP workers, PHP memory limit, bandwidth, backup retention, SSH access, SSL certificates, and custom error pages.
Yes. Changing a web space's resource plan takes effect immediately and triggers a reprovisioning job to update PHP-FPM and Nginx configurations with the new limits.
A template defines how Nginx handles requests for a domain — whether it serves static files, proxies to PHP-FPM for WP or Joomla, adds Varnish caching, or serves pre-built static sites like Jekyll.
No. Static and Jekyll templates serve content directly without PHP. CMS templates like WP and Joomla require a PHP version to be assigned to the domain.
SetModus integrates with Let's Encrypt to automatically issue and renew free SSL certificates. Admins, clients, and resellers can request certificates from their respective portals with a single click.
The domain health dashboard shows SSL status at a glance — green for valid, yellow for expiring within 30 days, and red for expired. Web space show pages display an aggregate SSL summary across all domains.
SetModus provisions MariaDB databases with dedicated users. Admins can create, delete, and rotate passwords from the admin panel. Database limits are controlled by the resource plan assigned to each web space.
Yes. The client portal provides read-only access to database details including name, username, and size. Password rotation and database creation are admin-level operations.
Yes. The WP Toolkit lets admins, clients, and resellers install, scan, clone, and back up WP sites. It includes updates, security scanning, user management, and configuration editing via WP-CLI integration.
Yes. Install WP on any web space with a single action. The system downloads the latest version, configures the database connection, and sets correct file permissions automatically.
Yes. Use Scan for WP to auto-discover all WP installations in a web space, or Add Existing to manually register a specific path. Both methods detect the version, admin user, and database via WP-CLI without modifying any files. Once registered, you can update, scan, backup, clone, and configure the site from the dashboard.
Each web space runs under its own dedicated system user (usr_<id>) with a separate PHP-FPM pool. File permissions prevent any web space from reading or modifying files belonging to another. A compromised site cannot access its neighbors.
SetModus enforces strict ownership: the web space directory is owned by its system user with group access for the web server (mode 0750). Temp directories are locked to the system user only (mode 0700). Only root can create new web space directories under /var/www/.
Yes. Each domain has its own tmp/ directory that is not shared with other domains or the system /tmp. This prevents session hijacking and cross-site data leakage through shared temporary files.
Server tokens are hidden, directory listing is disabled globally, and all dotfiles (.env, .git, etc.) are blocked by default. Symlink following is restricted to owner-matched files to prevent cross-space file reads.
Yes. Nginx denies access to all dotfiles (e.g., .env, .git/config, .htpasswd) with a blanket deny all rule. ACME challenge paths for SSL certificates are explicitly allowed and take priority.
Yes. The application forces SSL in production — all traffic is served over HTTPS. HTTP security headers including Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, and Referrer-Policy are set on every response.
Passwords require a minimum of 12 characters with uppercase, lowercase, digit, and special character. They are hashed with bcrypt (cost factor 11). Password change and email change notifications are sent automatically. Session timeout is 30 minutes.
Yes. The admin panel and CLI support both a safelist (always allowed) and blocklist (always denied) for individual IPs, CIDR ranges, and IP sets. These lists are refreshed every 5 minutes and checked on every request.
Login attempts are throttled at two levels: 5 per minute per IP and 5 per minute per email address. This stops both single-source brute-force and credential-stuffing attacks that rotate IPs. After 5 failed attempts, the account is locked for one hour with a warning on the final attempt.
Yes. All requests are throttled to 300 per 5 minutes per IP (~1 request/second sustained). Password reset requests are further limited to 3 per minute per IP to prevent reset flooding.
Yes. Resource-intensive actions have their own stricter limits: provisioning is limited to 5 per 5 minutes, backups and restores to 3 per 10 minutes, SSL certificate requests to 5 per 10 minutes, and emergency reinstalls to 2 per 10 minutes — all per IP.
Requests targeting malicious paths — path traversal sequences (..), server-side script extensions (.php, .asp, .jsp, .cgi, .env), and WP login probes — are automatically detected. After 3 hits within 10 minutes, the source IP is banned for one hour.
The server returns a plain 429 Too Many Requests response with no details about the rate-limit internals. Safelisted IPs bypass all throttles. Blocklisted IPs are denied before any throttle check runs.
Every state-changing action is recorded — resource creation, updates, deletion, status transitions, login attempts, lockouts, password changes, and configuration updates. Each entry includes the user, action, timestamp, and IP address.
SetModus includes a domain health checker that verifies HTTP/HTTPS connectivity, SSL certificate validity, and response status for each domain. Results are cached and displayed in the admin panel and client portal with color-coded badges.
Yes. Admins can configure HTTP basic authentication on any directory within a web space. This adds a username/password prompt before visitors can access the protected content — useful for staging sites or private areas.
SSH uses public key authentication only — no passwords. Keys are managed through the control panel and validated against supported formats (RSA, Ed25519, ECDSA). System users run with a nologin shell by default; SSH access is granted only when the resource plan permits it.
SSH keys map to Unix system users, and each web space has its own system user (usr_<id>). When you SSH in, you authenticate as a system user — not a client. This lets you assign different keys to different web spaces: a deploy key for production, a personal key for staging, and a CI key for testing — each with independent access control.
All existing SSH keys are removed on transfer. The new owner must add their own keys — the previous client's keys never carry over. This prevents former owners from retaining file access after a transfer.
Three reasons: (1) SSH authenticates against a Unix system user, not a client identity — keys must map to the system user that owns the files. (2) On web space transfer, all keys must be wiped for security — client-level keys would require complex untangling. (3) SSH access is gated by the web space's resource plan, not the client — a client could have one space with SSH and another without.
Set a default SSH public key on the client's profile. When a new web space is created and the resource plan allows SSH, the default key is automatically deployed. This gives you the convenience of client-level keys without sacrificing per-web-space control — the deployed key still belongs to the web space and can be independently removed or replaced.
Backups are created as compressed archives and stored under /var/backups/setmodus/ with restricted permissions. Each backup is tied to a web space and includes files and database dumps. Retention is configurable per resource plan.
All shell execution is routed through a single audited service (CommandRunner) — no raw shell calls are allowed anywhere else in the codebase. Commands use array-form arguments to avoid shell interpretation, every command declares a timeout, and all user input is escaped. SQL queries use parameterized statements exclusively — string interpolation in queries is blocked by automated security scans.
Every user-supplied path is validated with a strict regex, explicitly checked for .. sequences, and then resolved with File.realpath to follow symlinks. The resolved path must fall within the expected directory prefix. This three-layer defense applies to domain paths, PHP config paths, log downloads, and backup/restore operations.
All outbound HTTP connections follow a resolve-once-connect-to-IP pattern: the hostname is resolved once, the IP is validated against a blocklist of private ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 169.254.0.0/16), and the connection is made directly to the validated IP. This prevents DNS rebinding and server-side request forgery.
All secrets are stored in Rails encrypted credentials — never in source code, config files, or environment files. Credential files on disk are created with 0600 permissions atomically (no window where they are world-readable). Sensitive fields are filtered from all logs, and the application refuses to boot without its decryption key.
SetModus follows strict Rails conventions: thin controllers handle request/response only, service objects encapsulate business logic, background jobs handle system changes asynchronously, and Provisioner recipes manage all server-level configuration. No controller directly executes shell commands or writes config files.
A controller queues a background job → the job invokes Provisioner with node attributes exported from validated models → Configuration Management Client recipes run in a fixed order (user → directories → ssh → nginx → domain → php → varnish → mariadb) → the outcome is logged. This pipeline ensures changes are atomic, ordered, and auditable.
Over 30 system invariants are enforced at all times: every web space has a matching directory and a primary domain, no two domains share the same hostname, no symlinks escape /var/www/, UIDs match web space IDs, and the audit log is append-only. These are enforced by database constraints, model validations, and nightly scans.
The application has no blanket root access. Each system command that needs sudo has an explicit entry in a sudoers allowlist. File removal goes through a path-validated wrapper that only permits deletions under managed directories. Every privileged command is logged with the caller, duration, and result.
Yes. A built-in security audit (bin/rails security:audit) scans for shell execution bypasses and SQL injection patterns before every change. Static analysis (Brakeman) checks for OWASP Top 10 vulnerabilities, and dependency audits flag known CVEs in gems. All security fixes require regression tests.
Yes. The bin/sm CLI provides full management capabilities — add domains, manage Nginx/PHP/Varnish versions, control IP safelists and blocklists, run provisioning, and inspect logs. Everything available in the admin panel can be scripted.
Use bin/sm domain add DOMAIN WEB_SPACE_ID TEMPLATE. Optional flags include --nginx VERSION, --php-version VERSION, --no-active (skip activation), and --no-provision (skip provisioning). The domain is created, activated, and provisioned in one command by default.
Each stack component has add, activate, and deactivate subcommands: bin/sm nginx add VERSION, bin/sm php add VERSION, bin/sm varnish add VERSION. Adding a version installs the package and triggers provisioning automatically.
Use bin/sm safelist add IP, bin/sm safelist remove IP, and bin/sm safelist list — same for blocklist. Both accept individual IPs and CIDR ranges. Changes take effect within 5 minutes via the cached configuration refresh.
Use bin/sm publish deploy for a full run, or bin/sm publish recipes RECIPE [...] for specific recipes (e.g., publish recipes nginx domain). Recipes are automatically sorted into the correct dependency order. Check the current mode with publish status and inspect the latest output with publish log.
Use the show subcommand: bin/sm show domains, show nginx, show php, show varnish, and show ipsets. Each lists all records of that type with their current status.
Publishing applies configuration changes to the server. When you create, modify, or delete a domain or web space, a background job runs Configuration Management Client recipes to update SSH, Nginx, PHP-FPM, and Varnish configurations.
In dry-run mode, provisioning jobs are simulated without making real system changes. This lets you develop and test safely. The mode is controlled in Admin → Settings.
Yes. Admins can export clients, web spaces, and domains to CSV. PDF reports and monthly usage reports are available for resellers, summarizing resource consumption across their accounts.
SetModus can send webhook notifications for key events — domain registration, SSL certificate updates, status changes, and more. Configure webhook URLs in Admin → Settings.
Yes. Admins can schedule maintenance windows with automatic banner alerts displayed to all users. Clients can set their own emergency maintenance windows to override scheduled downtime if needed.
Admins can tag clients, web spaces, and domains for filtering and organization. Notes can be attached to any entity with pinning support, making it easy to track context and decisions across the panel.
Yes. A global search bar (keyboard shortcut /) searches across all clients, resellers, domains, and web spaces instantly. Results are grouped by type with direct links.