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 sudo access (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 denied when writing to logs or cache
  • EACCES errors during npm/vite builds
  • Failed to open stream in 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