Docs / Deployment Guide
🏠 Home

Backend Deployment Guide

Everything needed to take the CargoPRO admin backend to a production server: requirements, web server configuration, PHP settings, folder permissions, and process management for the queue worker and scheduler.

Shared hosting or VPS? The installation guide walks through the web installer on cPanel and a VPS. This page is the production reference that goes deeper: exact server configuration files, the supervisor/systemd units for background processing, and the update procedure. On shared cPanel hosting, use the cron fallback described in Process management.

Server requirements

ComponentRequirementNotes
PHP8.2 or newerExtensions: pdo_mysql, mbstring, openssl, tokenizer, xml, ctype, json, fileinfo, curl; optional gd + bcmath (image handling / arithmetic). The installer verifies all of these in step 2.
DatabaseMySQL 5.7+ / MariaDB 10.3+An empty database + a dedicated user with all privileges on it. The installer can create the database if the user has CREATE rights.
Web serverNginx or Apache 2.4+Document root must point at the public/ folder β€” see Web server configuration.
Composer2.xOnly needed if you deploy from source without vendor/.
Node.js18+ (build-time only)Only to rebuild frontend assets with npm run build; the compiled public/build ships ready-to-use.
PHP settingsupload_max_filesize & post_max_size ≥ 20M, max_execution_time ≥ 120Pre-alert and shipment files are up to 10 MB each; raise the limits if you accept larger uploads.
OptionalRedis, SSL certificate, cronRedis improves queue/cache throughput at scale; SSL is effectively mandatory; cron (or supervisor) drives the scheduler.

The Flutter apps have their own toolchain requirements β€” see Requirements & Stack for the full table including Flutter and Android Studio versions.

Web server configuration

The single most important rule: the document root must point at the public/ folder, never at the project root. That keeps .env, storage/, vendor/ and the database files unreachable from the web.

Server block for /etc/nginx/sites-available/cargopro (symlink it into sites-enabled):

server {
    listen 80;
    listen [::]:80;
    server_name your-domain.com;
    root /var/www/cargopro/public;   # <-- the public folder

    index index.php;
    client_max_body_size 25M;        # match your PHP upload limits

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    }

    location ~ /\.(?!well-known).* {
        deny all;                    # block dotfiles except ACME challenges
    }
}

Enable it and reload:

sudo ln -s /etc/nginx/sites-available/cargopro /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

VirtualHost for /etc/apache2/sites-available/cargopro.conf:

<VirtualHost *:80>
    ServerName your-domain.com
    DocumentRoot /var/www/cargopro/public   # <-- the public folder

    <Directory /var/www/cargopro/public>
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/cargopro-error.log
    CustomLog ${APACHE_LOG_DIR}/cargopro-access.log combined
</VirtualHost>

The shipped public/.htaccess handles front-controller rewriting β€” it only needs mod_rewrite enabled and AllowOverride All:

sudo a2enmod rewrite
sudo a2ensite cargopro
sudo systemctl reload apache2

HTTPS / SSL

HTTPS is effectively mandatory β€” the apps talk to the API over the network, mixed content is blocked by stores, and secure cookies need it. With Certbot on a VPS:

sudo certbot --nginx -d your-domain.com      # or --apache

Certbot rewrites the server block for automatic renewal. On cPanel use SSL/TLS Status → Run AutoSSL. After enabling HTTPS, make sure APP_URL=https://your-domain.com in .env so generated links match.

Folder permissions

Laravel must be able to write to two locations (the installer checks them in step 3). On a VPS where the site runs as www-data:

sudo chown -R www-data:www-data /var/www/cargopro/storage /var/www/cargopro/bootstrap/cache
sudo find /var/www/cargopro/storage -type d -exec chmod 775 {} \;

Everything else can stay owned by your deploy user and read-only for the web server.

Process management (queue worker & scheduler)

The installer sets QUEUE_CONNECTION=database. Two background processes keep CargoPRO running:

ProcessWhat it drivesHow
Queue workerBulk email/SMS/WhatsApp and push notification fan-outphp artisan queue:work β€” a long-running process managed by supervisor or systemd (below), or cron on shared hosting
SchedulerRecurring maintenance tasksphp artisan schedule:run every minute via cron β€” on every hosting type

Supervisor (recommended for VPS)

Supervisor keeps the queue worker alive, restarts it if it crashes, and starts on boot. Create /etc/supervisor/conf.d/cargopro-worker.conf:

[program:cargopro-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/cargopro/artisan queue:work --sleep=3 --tries=3 --timeout=300
autostart=true
autorestart=true
stopwaitsecs=3600
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/cargopro/storage/logs/worker.log
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start "cargopro-worker:*"

numprocs=2 runs two workers; one is plenty for most installs. stopwaitsecs must exceed your longest job so a deploy does not kill a notification batch mid-flight.

systemd (alternative)

If you prefer plain systemd, save as /etc/systemd/system/cargopro-worker.service:

[Unit]
Description=CargoPRO queue worker
After=network.target mysql.service

[Service]
User=www-data
Restart=always
RestartSec=5
ExecStart=/usr/bin/php /var/www/cargopro/artisan queue:work --sleep=3 --tries=3 --timeout=300

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now cargopro-worker

Cron (shared hosting / cPanel)

Where you cannot run daemons, two cron jobs emulate both processes β€” add them in cPanel → Cron Jobs (adjust the path):

* * * * * cd /home/USER/public_html && php artisan schedule:run >> /dev/null 2>&1
* * * * * cd /home/USER/public_html && php artisan queue:work --stop-when-empty --max-time=50 >> /dev/null 2>&1

The second job drains the queue every minute and exits after 50 seconds, so jobs never overlap. The scheduler entry is always required regardless of hosting type.

Deploying an update

When you ship a new version of the backend to an existing server:

php artisan down                     # maintenance mode (optional)
# ... upload/extract the new files, keep the existing .env ...
composer install --no-dev --optimize-autoloader   # if vendor/ is not shipped
php artisan migrate --force          # apply schema updates
php artisan storage:link             # no-op if it exists
php artisan config:cache && php artisan route:cache && php artisan view:cache
php artisan queue:restart            # workers pick up the new code
php artisan up
Always restart workers after a deploy queue:work holds code in memory. Without queue:restart (or supervisorctl restart) it keeps running the previous release until it dies naturally.

Production hardening checklist

Security

  • Debug off β€” the installer writes APP_ENV=production and APP_DEBUG=false; confirm with php artisan about.
  • HTTPS β€” SSL active and APP_URL=https://… matching it.
  • Installer locked β€” the storage/app/installed marker blocks the wizard from re-running. Back it up together with .env.
  • Strong admin password β€” the finish page shows it once; change it under Profile if it was shared anywhere.
  • Document root on public/ β€” never the project root (see Web server configuration).

Background processing

  • Queue worker running β€” supervisor/systemd on a VPS, the cron fallback on shared hosting; verify with php artisan queue:monitor or by sending a test notification.
  • Scheduler cron installed β€” schedule:run every minute.
  • Storage link present β€” php artisan storage:link (re-run after moving the site).

Performance & data safety

  • Caches primed β€” config:cache, route:cache, view:cache (skip config:cache on cPanel if you edit .env often; re-run after any edit).
  • Backups enabled β€” Tools → Backups, and download one copy off-server after go-live.
  • End-to-end test β€” register → pre-alert → package → payment → tracking from a private browser window.