SSH Access & File Permissions
ServerPlane manages your servers over SSH using a dedicated serverplane system user. Each deployed application gets its own isolated system user and directory. Understanding how users, permissions, and directories are structured helps you troubleshoot issues and perform manual operations when needed.
Server Users
The serverplane user
When you provision a server, ServerPlane creates a serverplane user with passwordless sudo access. All platform operations (deployments, stack installations, configuration changes) run as this user over SSH. You should not modify or delete this user.
Application users
Each application you deploy gets its own system user, named after the app (e.g., sp_myapp_uXYZ). This user:
- Owns the application files
- Runs PHP-FPM, PM2, Gunicorn, or other app processes
- Executes cron jobs and daemons configured in the dashboard
- Has no
sudoaccess (isolated from other apps and the system)
You can see the system user for any app in App > Overview.
Directory Structure
Each application lives under /home/{system_user}/:
/home/sp_myapp_uXYZ/
├── app/ # Application code (or symlink target for atomic deploys)
│ ├── public/ # Web root (served by Nginx)
│ ├── storage/ # Laravel storage, logs, cache
│ ├── .env # Environment variables
│ └── ...
└── logs/ # Daemon log files (if using Daemons feature)
For atomic deploys, the structure includes releases:
/home/sp_myapp_uXYZ/
├── releases/
│ ├── 20260405_120000/ # Previous release
│ └── 20260405_143000/ # Current release
├── current -> releases/20260405_143000 # Symlink to active release
├── storage/ # Shared storage (persists across releases)
└── logs/
SSHing Into Your Server
As the serverplane user
ssh serverplane@YOUR_SERVER_IP
Use this when you need sudo access for system-level operations (installing packages, restarting services, editing Nginx configs).
As the application user
ssh serverplane@YOUR_SERVER_IP
sudo -u sp_myapp_uXYZ bash
cd ~/app
Use this when running application commands. This ensures files you create have the correct ownership.
Running Application Commands
Always run application commands as the app user, not as root or serverplane. This prevents permission issues.
Laravel
sudo -u sp_myapp_uXYZ php artisan migrate
sudo -u sp_myapp_uXYZ php artisan config:cache
sudo -u sp_myapp_uXYZ php artisan queue:restart
sudo -u sp_myapp_uXYZ composer install —no-dev
Node.js
sudo -u sp_myapp_uXYZ npm install
sudo -u sp_myapp_uXYZ npm run build
sudo -u sp_myapp_uXYZ pm2 restart all
Python
sudo -u sp_myapp_uXYZ pip install -r requirements.txt
sudo -u sp_myapp_uXYZ python manage.py migrate
WordPress
sudo -u sp_myapp_uXYZ wp plugin update —all
sudo -u sp_myapp_uXYZ wp cache flush
Fixing Permission Issues
If you accidentally run commands as root or serverplane, files may end up with the wrong ownership. This causes errors like:
Permission deniedwhen writing to logs or cacheEACCESerrors during npm/vite buildsFailed to open streamin PHP
Fix ownership for the entire app
sudo chown -R sp_myapp_uXYZ:sp_myapp_uXYZ /home/sp_myapp_uXYZ/app
Fix Laravel storage and cache specifically
sudo chown -R sp_myapp_uXYZ:sp_myapp_uXYZ /home/sp_myapp_uXYZ/app/storage
sudo chown -R sp_myapp_uXYZ:sp_myapp_uXYZ /home/sp_myapp_uXYZ/app/bootstrap/cache
sudo chmod -R 775 /home/sp_myapp_uXYZ/app/storage
sudo chmod -R 775 /home/sp_myapp_uXYZ/app/bootstrap/cache
Fix node_modules after running npm as root
sudo chown -R sp_myapp_uXYZ:sp_myapp_uXYZ /home/sp_myapp_uXYZ/app/node_modules
Common Gotchas
Running commands as root breaks permissions
If you SSH in as root and run npm install, composer install, or php artisan commands, the generated files will be owned by root. The web server (running as the app user) won't be able to read or write them. Always use sudo -u {app_user} for application commands.
Config cache uses wrong values
If you run php artisan config:cache as root, it may read a different .env file or shell environment. Always run it as the app user:
sudo -u sp_myapp_uXYZ php artisan config:cache
Vite build fails with EACCES
This happens when node_modules or public/build is owned by a different user. Fix ownership first, then rebuild:
sudo chown -R sp_myapp_uXYZ:sp_myapp_uXYZ /home/sp_myapp_uXYZ/app
sudo -u sp_myapp_uXYZ npm run build
Restarting services requires sudo
Application processes are managed by system services. To restart them manually:
# PHP-FPM (Laravel/WordPress/PHP apps)
sudo systemctl restart php8.4-fpm
# Nginx
sudo systemctl reload nginx
# PM2 (Node.js apps)
sudo -u sp_myapp_uXYZ pm2 restart all
# Gunicorn (Python apps)
sudo systemctl restart gunicorn-sp_myapp_uXYZ
# Supervisor daemons
sudo supervisorctl restart sp-daemon-{app_id}-{daemon_id}:*
File Permissions Reference
| Path | Owner | Permissions | Notes |
|---|---|---|---|
/home/{user}/app/ |
App user | 755 | Application root |
/home/{user}/app/storage/ |
App user | 775 | Must be writable by app |
/home/{user}/app/bootstrap/cache/ |
App user | 775 | Must be writable by app |
/home/{user}/app/.env |
App user | 640 | Readable by app user only |
/home/{user}/app/public/ |
App user | 755 | Served by Nginx |
/home/{user}/logs/ |
App user | 755 | Daemon log output |
/etc/nginx/sites-enabled/ |
root | 644 | Nginx vhost configs |
/etc/supervisor/conf.d/ |
root | 644 | Supervisor daemon configs |