Install SimpliFi on shared hosting with the web installer, cron, SSL and wildcard subdomains.

Deploying SimpliFi on cPanel

This guide installs SimpliFi on ordinary cPanel shared hosting without SSH: upload one zip, run the web installer, add one cron job. It also covers wildcard subdomains and SSL, payment webhooks, SMS, the first router, upgrades and backups.

Everything here works on a VPS with cPanel too. Without cPanel, the same ideas apply: PHP 8.2+, MySQL/MariaDB, a web server whose document root is public/, one cron entry.


1. What you need

Item Notes
cPanel hosting with PHP 8.2 or newer "Select PHP Version" (CloudLinux) or "MultiPHP Manager"
PHP extensions pdo_mysql, mbstring, openssl, curl, gd, zip, fileinfo, bcmath, json, tokenizer, ctype, xml (+ intl recommended)
MySQL 5.7+/8 or MariaDB 10.3+ one database + one user
A domain e.g. simplifi.henapp.org (the base domain)
Wildcard DNS *.base-domain only for subdomain mode (each ISP gets name.base-domain)
SSL AutoSSL / Let's Encrypt (see §6)
Cron one entry, every minute

You build the zip on your own computer (Windows): Node 18+, Composer 2 and PHP 8.2 must be installed there.


2. Build the upload package (on your computer)

From the project folder, in PowerShell:

.\package-for-cpanel.ps1

The script:

  1. runs npm run build (compiled CSS/JS go to public/build, so the server needs no Node);
  2. copies the app to a temporary staging folder without node_modules, .git, tests, storage logs / caches / sessions, local .env, database/database.sqlite and old zips;
  3. runs composer install --no-dev --optimize-autoloader in the staging folder — vendor/ is shipped because most shared plans have no SSH / Composer;
  4. writes an installer-ready .env from .env.example (production, fresh temporary APP_KEY, file sessions/cache, SIMPLIFI_INSTALLER=true, path mode until you choose);
  5. zips everything as dist\simplifi-cpanel-YYYYMMDD-HHmm.zip (forward-slash paths, safe for Linux unzip and cPanel File Manager).

Options: -SkipBuild (reuse the current public/build), -SkipComposer (reuse vendor/ — only if it was installed with --no-dev), -OutputDir C:\builds, -KeepStaging.


3. Create the database

cPanel › MySQL® Databases:

  1. Create New Database: e.g. simplifi → becomes cpuser_simplifi.
  2. Add New User: e.g. simplifi with a long generated password → cpuser_simplifi.
  3. Add User To Database → tick ALL PRIVILEGES.

Keep the three values (database, user, password) for the installer. The host is localhost.


4. Upload and point the domain

  1. cPanel › File Manager → your home folder (not public_html) → create simplifi/.
  2. Upload the zip into simplifi/ and Extract it. You should see app/, public/, vendor/, .env, artisan … inside simplifi/.
  3. Point the domain's document root to simplifi/public:
    • Addon / sub domain: cPanel › Domains › Manage › New Document Root = simplifi/public.
    • Primary domain whose root you cannot change (public_html): either extract SimpliFi into public_html and copy cpanel.htaccess to public_html/.htaccess (it forwards everything to public/ and blocks .env, vendor/, storage/ …), or replace public_html by a symlink to simplifi/public if your host allows it.
  4. File permissions: folders 755, files 644; storage/ and bootstrap/cache/ must be writable by PHP (they are on standard cPanel/suPHP/LSAPI setups).

PHP version and extensions

cPanel › Select PHP Version (or MultiPHP Manager): choose 8.2+ for the domain, then the Extensions tab: tick everything listed in §1. Recommended options: memory_limit 256M, max_execution_time 120, upload_max_filesize 16M, post_max_size 20M.


5. Run the web installer

Open https://your-domain/ — every page redirects to /install until the platform is installed.

  1. Requirements — PHP version, extensions and writable folders (fix anything red, then Check again).
  2. Database — host localhost, port 3306, database, user, password → Test connection. The password is never shown again on screen.
  3. Application — platform name, main URL (with https://), base domain, and how ISPs get their address:
    • Subdomains (recommended): henapp.simplifi.henapp.org — needs §6.
    • Paths: simplifi.henapp.org/henapp — no DNS work; good for a first test. Support e-mail / phone / WhatsApp appear on the website and in messages. Optional SMTP: create a mailbox (cPanel › Email Accounts, e.g. no-reply@your-domain) and use its Connect Devices settings (SSL, port 465).
  4. Super admin — your platform owner account (10+ characters, upper/lower case + numbers).
  5. Install — creates the tables (migrate --force), saves platform settings, creates the super admin, tries storage:link, writes a new .env atomically with a fresh APP_KEY, production settings and database sessions / cache / queue, sets SIMPLIFI_INSTALLER=false, writes storage/app/installed.lock and clears caches.
  6. Finish shows the cron command and next steps.

After installation /install answers 404. To run it again (fresh server, broken .env): set SIMPLIFI_INSTALLER=true in .env and delete storage/app/installed.lock. Re-running keeps existing data (migrations only add what is missing) and updates the super admin with the same e-mail.

No symlinks allowed? Fine: uploaded logos and files are streamed through /media/... automatically when public/storage does not exist.


6. Wildcard subdomains and SSL (subdomain mode)

Each ISP workspace lives on name.base-domain, e.g. henapp.simplifi.henapp.org.

  1. DNS: add *.simplifi.henapp.org → same IP as simplifi.henapp.org (A record), or a CNAME to it. With cPanel DNS: Zone Editor › + A Record name *.
  2. cPanel › Domains › Create A New Domain: *.simplifi.henapp.org with document root the same simplifi/public folder (untick "share document root" only if your cPanel asks for a separate one — it must be the same folder).
  3. SSL:
    • AutoSSL issues a certificate for each name it can validate. Wildcard certificates need DNS validation: cPanel's Let's Encrypt plugin can issue *.domain only when the DNS zone is hosted on the same cPanel/WHM server (or its DNS cluster) — see https://docs.cpanel.net/knowledge-base/third-party/the-lets-encrypt-plugin/.
    • DNS hosted elsewhere (e.g. Cloudflare): either move the zone to cPanel, use Cloudflare's proxy with an Origin Certificate for *.domain, or ask your host for a wildcard certificate. Behind Cloudflare (or any reverse proxy) tick "This site is behind Cloudflare or another reverse proxy" in the installer's Application step, or set TRUSTED_PROXIES=* in .env: otherwise every visitor shares the proxy's IP for rate limits and activity logs. Leave it unset when visitors reach the server directly.
    • Until the wildcard SSL works you can run in path mode (TENANCY_MODE=path in .env).
  4. Custom domains for ISPs (Settings › Domain in each workspace): the ISP adds a CNAME to the base domain (or an A record to the server IP) and the TXT record simplifi-verify=… on _simplifi.their-domain. You add their domain as an Alias (cPanel › Domains, same document root) so Apache serves it, and AutoSSL covers it. The workspace shows "Verified" once DNS points to you; links then switch to the custom domain.

SESSION_DOMAIN stays empty: each host keeps its own login session.


7. Cron job and queue (required)

cPanel › Cron Jobs › Once Per Minute (* * * * *):

/usr/local/bin/php /home/CPANELUSER/simplifi/artisan schedule:run >> /dev/null 2>&1

(The installer's Finish page prints the exact line for your server; use ea-php82 paths such as /opt/cpanel/ea-php82/root/usr/bin/php if your host documents them. Always the php CLI — never lsphp, php-cgi or php-fpm: started from cron those run in CGI mode and, with cPanel's register_argc_argv=Off, silently run artisan's default list command every minute instead of schedule:run.) The installer's requirements page also checks that proc_open is not in disable_functions: every scheduled task is started through it, so without it cron "runs" and nothing happens.

The scheduler runs everything — no daemons are needed:

  • the queue (queue:work --stop-when-empty --max-time=50, every minute): welcome SMS, campaigns, notifications;
  • router monitoring and MikroTik cloud-sync housekeeping;
  • hotspot expiry and reminders, PPPoE invoices and suspensions;
  • payment reconciliation (pending MoMo prompts);
  • platform billing (daily 06:00).

If cron stops, payments still complete when customers return to the pay page, but reminders, expiries and queued SMS wait until it runs again.


8. Payments, SMS and webhooks

Sign in as super admin (https://base-domain/login).

  • Platform gateways (Super admin › Payment gateways): Henapp's own Paystack/Hubtel account, used for ISP invoices, SMS credits and platform-split collections.
  • ISP gateways (each workspace › Settings › Payments).
  • Webhook URLs are shown next to every gateway, in the form https://base-domain/webhooks/payments/{driver}/{gateway id}:
    • Paystack: Dashboard › Settings › API Keys & Webhooks › Webhook URL.
    • Hubtel: callbacks are unsigned hints that trigger a status check — ask Hubtel to enable Direct Receive Money and to whitelist your server's public IP for the status API.
    • MTN MoMo: payments are confirmed by polling; tick "Send our callback URL" only when the API user's callback host is this server.
    • Return URL after hosted checkout: /webhooks/payments/return/{payment} (automatic). See Payments for keys, test numbers and troubleshooting.
  • SMS (Super admin › SMS): paste the smsfactory.henapp.org (Zenoph) API key and sender ID. .env must have SMS_DRIVER=zenoph (the installer sets it). ISPs can buy credits or use their own key under Settings › SMS.
  • WhatsApp (per workspace): webhook https://base-domain/webhooks/whatsapp/{workspace id}.

9. First MikroTik router

  1. Create a workspace (/signup, or Super admin › Tenants › New).
  2. In the workspace: Devices › Routers › Add router › MikroTik › Cloud Sync.
  3. Paste the generated one-line script into the router terminal (Winbox › New Terminal).
  4. The router appears online within a minute. No public IP, port forwarding or VPN needed.

Details: MikroTik setup. Other brands: Vendors, RADIUS (FreeRADIUS on a small VPS reading this database through cPanel Remote MySQL).


10. Upgrading

  1. Build a new zip (package-for-cpanel.ps1).
  2. Back up first (§11).
  3. Upload and extract it over the existing folder, but do not overwrite:
    • .env (your configuration and APP_KEY — losing the key makes encrypted gateway/SMS keys unreadable),
    • storage/ (uploads, logs, installed.lock). The simplest way: delete .env and the storage/ folder from the zip before uploading (7-Zip › open the zip › delete), or extract to simplifi-new/ and move folders across.
  4. Run the database changes. Without SSH, use a temporary cron line (runs once, then delete it):
    /usr/local/bin/php /home/CPANELUSER/simplifi/artisan migrate --force && /usr/local/bin/php /home/CPANELUSER/simplifi/artisan optimize:clear
    
    With SSH: php artisan migrate --force && php artisan optimize:clear.
  5. Patch zips (only changed files) work the same way; always include public/build when CSS/JS changed.

11. Backups

  • Database: cPanel › Backup › Download a MySQL Database Backup (daily for busy platforms), or a cron mysqldump to a folder outside public.
  • Files: storage/app/public (logos, uploads) and .env — keep a copy of .env somewhere safe: the APP_KEY inside it decrypts saved gateway and SMS keys.
  • Test a restore on a staging subdomain now and then.

12. Security checklist

  • APP_DEBUG=false, APP_ENV=production (set by the installer).
  • Document root is public/ (or cpanel.htaccess is in place): https://your-domain/.env must return 403/404.
  • HTTPS everywhere; public/.htaccess sends security headers (no-sniff, frame-origin, referrer policy, HSTS on HTTPS).
  • Strong, unique super-admin password; remove unused staff accounts.
  • Keep PHP updated through cPanel; keep at least weekly backups.

13. Installable apps (PWA) and Google Play

SimpliFi is a Progressive Web App: the admin (/admin), the captive portal (/portal) and the platform site each have a web manifest, icons and a service worker (public/sw.js). On Android Chrome an Install banner appears automatically; on iPhone users see "Share › Add to Home Screen" instructions. Workspace icons are generated from the ISP's logo (Settings › General).

To publish an Android app on Google Play, wrap the PWA as a Trusted Web Activity with PWABuilder (docs: https://docs.pwabuilder.com/#/builder/android):

  1. The site must be live on HTTPS. Open https://www.pwabuilder.com/, enter the URL to package — e.g. https://henapp.simplifi.henapp.org/admin for one ISP's admin app (or their custom domain), or the base domain for a platform-wide app.
  2. Package for stores › Android › Google Play. Check the package ID (e.g. org.henapp.simplifi.henapp), app name, colours and icons (taken from the manifest); create a new signing key.
  3. Download the zip: it contains the .aab (upload to Play Console), signing.keystore + signing-key-info.txt (keep them safe — needed for every update) and assetlinks.json.
  4. Upload assetlinks.json to /.well-known/assetlinks.json on the same host as the start URL: put it in public/.well-known/assetlinks.json (all subdomains share the folder; for several apps on different hosts, merge their entries into one JSON array).
  5. After the first Play upload, Google re-signs the app: copy the SHA-256 fingerprint from Play Console › Setup › App integrity › App signing into sha256_cert_fingerprints in assetlinks.json and upload it again — the browser address bar then disappears.
  6. Updates: generate a new package with a higher version code and the same signing key. Web changes appear in the app immediately; no store update is needed for them.

Background: https://web.dev/articles/using-a-pwa-in-your-android-app.


14. Troubleshooting

Symptom Fix
Every page goes to /install after installing storage/app/installed.lock missing or SIMPLIFI_INSTALLER=true with no lock: re-run the installer or set it to false.
500 error, blank page Check storage/logs/laravel.log; make storage/ and bootstrap/cache/ writable; PHP version 8.2+.
CSS missing / unstyled pages public/build was not uploaded — rebuild the package without -SkipBuild.
"Workspace not found" on name.domain Wildcard DNS / subdomain missing, or SIMPLIFI_BASE_DOMAIN wrong in .env.
Logos do not show public/storage link missing is fine (served via /media); check storage/app/public permissions.
SMS not delivered Super admin › SMS › Test; SMS_DRIVER=zenoph; sender ID approved.
Payments stay pending Cron not running (reconciliation), or webhook URL not set at the gateway.
Router offline See MikroTik setup troubleshooting; check the router can reach https://base-domain.

Ready to try it on your network?

Start your 14-day free trial today. Set up in minutes, no credit card, cancel any time.

Install SimpliFi App

One tap, no app store. Faster, full screen, works on weak signal.