7.1 KiB
WordOps Dev Panel
A lightweight internal control panel for managing WordOps WordPress sites without forcing developers onto the CLI.
What this does
- Lists WordOps sites (hides
dev-panel.local) - Create / delete sites via WordOps
- Optional bootstrap step after site creation (
wp-dev-bootstrap.sh) - User auth + roles:
admincan see/manage all sites + manage usersdevcan only see/manage sites they created
- SQLite-backed storage (no external DB required)
- Password change modal + logout under a username dropdown
- Streaming output for long-running bootstrap (WordOps output may still arrive in chunks)
Requirements
Server
- Up-to-date Linux OS (built and tested on Ubuntu 24.04)
- WordOps installed and working (
/usr/local/bin/wo) - WP-CLI installed and working (
wpin PATH) - Nginx + PHP-FPM (WordOps provides this)
PHP packages
Install SQLite support for PHP (required):
sudo apt update
sudo apt install -y php-sqlite3
sudo systemctl restart php8.3-fpm || true
sudo systemctl restart php-fpm || true
Adjust
php8.3-fpmto your PHP version if needed.
File layout
Panel site lives at:
/var/www/<dev panel URL>/htdocs/index.php/var/www/<dev panel URL>/htdocs/includes/db.php/var/www/<dev panel URL>/htdocs/includes/functions.php/var/www/<dev panel URL>/htdocs/style.css/var/www/<dev panel URL>/htdocs/panel.sqlite (auto-created)
Scripts live at:
/usr/local/bin/wp-dev-bootstrap.sh/usr/local/bin/wo-fix-perms.sh(optional)
Install steps
-
Create the WordOps “panel” site
sudo wo site create <dev panel URL> --phpAdd host entry on your workstation (or internal DNS), then confirm you can load the site.
-
Drop in the panel files
Copy:
-
index.php→/var/www/<dev panel URL>/htdocs/index.php -
style.css→/var/www/<dev panel URL>/htdocs/style.cssMake sure the web server can write the SQLite DB (the panel will create it on first load):sudo chown -R www-data:www-data /var/www/<dev panel URL>/htdocsOptional: lock down later once seeded; see permissions section below
-
-
Install bootstrap + helper scripts
Copy:
wp-dev-bootstrap.sh→/usr/local/bin/wp-dev-bootstrap.sh(custom bootstrap script)wo-fix-perms.sh→/usr/local/bin/wo-fix-perms.sh(optional)
Then:
sudo chmod +x /usr/local/bin/wp-dev-bootstrap.shsudo chmod +x /usr/local/bin/wo-fix-perms.sh
-
Allow www-data to run WordOps + scripts via sudo
Create sudoers file:
sudo visudo -f /etc/sudoers.d/dev-panelContents:
www-data ALL=(root) NOPASSWD: /usr/local/bin/wo * www-data ALL=(root) NOPASSWD: /usr/local/bin/wp-dev-bootstrap.sh * www-data ALL=(root) NOPASSWD: /usr/local/bin/wo-fix-perms.sh *This lets the panel (running as www-data) execute the exact commands it needs as root.
Do not add
www-datato the sudo group.Test:
sudo -u www-data sudo /usr/local/bin/wo site list
First login / seeding
On first load, if there are no users, the panel auto-creates:
Username: admin
Password: change-me
Log in and change it immediately using the user dropdown → “Change password”.
Ownership & permissions strategy
You have two competing needs:
- WordPress / PHP needs to write certain files
- Developers need to edit themes/plugins without being root
A safe, simple model is group-based permissions.
# Create a shared dev group
sudo groupadd webdev || true
# Add all devs to group
sudo usermod -aG webdev <devUser1>
sudo usermod -aG webdev <devUser2>
...
# Add web server user
sudo usermod -aG webdev www-data
Log out and back in for group membership to apply.
Set group ownership + setgid under /var/www
sudo chown -R root:webdev /var/www
# Directories: 2775 (setgid + group writable)
sudo find /var/www -type d -exec chmod 2775 {} \;
# Files: 664 (group writable)
sudo find /var/www -type f -exec chmod 664 {} \;
Ensure new files stay group-writable
Make sure your bootstrap script starts with umask 0002
If WordOps creates files with different perms, run the optional fixer after site creation:
sudo /usr/local/bin/wo-fix-perms.sh example.local
SSH keys for private repos (bootstrap theme cloning)
If your bootstrap clones private repos, you’ll need a key that can access them.
Option A (recommended): deploy key or bot account key for the server
Create /var/www/.ssh/ or /home/<serviceUser>/.ssh/ depending on your model
Ensure correct perms:
/var/www/.sshor/home/<serviceUser>/.ssh= 700- private key = 600
Add to GitHub as a deploy key or bot account key
Ensure known_hosts contains github.com to avoid prompts:
sudo -u www-data ssh-keyscan github.com >> /var/www/.ssh/known_hosts
Option B: keep bootstrap theme cloning optional and run theme cloning from a dev account via VSCode Remote.
Don’t store a personal private key in a shared server environment.
Daily workflow
Option A: (recommended) VSCode Remote - SSH
- Devs connect via SSH to the server
- Edit project files directly under
/var/www/<site>/htdocs - Panel handles provisioning + bootstrap + ownership metadata
- No need for tooling (
node,php, etc) on user machines beyond VSCode + SSH
Option B: SMB shares (with SSH tunnel)
- Export
/var/www(or per-site roots) via Samba - Use group permissions (webdev) so edits behave identically to SSH
- Map network drives on dev machines
- Requires tooling (
node,php, etc) on user machines for composer, Tailwind, etc
Troubleshooting
“PDOException: could not find driver”
PHP SQLite extension missing:
sudo apt install -y php-sqlite3
sudo systemctl restart php8.3-fpm || sudo systemctl restart php-fpm
WordOps fails when run as www-data
Don’t run wo as www-data directly:
Correct (what the panel does):
sudo -u www-data sudo /usr/local/bin/wo site list
Incorrect:
sudo -u www-data /usr/local/bin/wo site list
WordOps delete prompts / EOFError
Use --no-prompt on deletes (panel already does).
Panel isn’t streaming output
Bootstrap output streams (proc_open + flush)
WordOps sometimes buffers; that’s normal. The panel will still show output when it arrives.
Security notes
The panel’s sudoers file is the main security boundary:
- Keep it as narrow as possible
- Avoid wildcarding unrelated commands
- Consider restricting panel access by:
- Internal network only
- VPN only
- HTTP basic auth in front of it
- Keep OS patches current
- Regularly audit panel users + roles
Backups (minimum viable)
At minimum, back up:
- /var/www (all site roots)
- Databases (WordOps MariaDB/MySQL)
/etc/nginxand WordOps configs (optional but helpful)- Panel SQLite DB:
/var/www/dev-panel.local/htdocs/panel.sqlite
Next steps / nice-to-haves
- “Fix perms” button in the panel post-create
- Per-site notes (who/why) for management visibility
- Audit log for create/delete/bootstrap actions
- Optional “clone template site” support