Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/0m1n3m/contacts-db/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks you through deploying Contacts DB to a production server — whether that is a bare VPS, a shared hosting environment, or a managed platform like Laravel Forge or Ploi. It covers environment configuration, database migration, asset compilation, queue workers, the task scheduler, and web server setup. Follow each step in order for a clean, repeatable deployment.
Always set APP_DEBUG=false in production. Leaving debug mode on exposes full stack traces, environment variable values, and internal application details to anyone who triggers an error — including unauthenticated visitors.

Pre-deployment checklist

1

Configure the environment file

Copy .env.example to .env on the server and set the core variables:
cp .env.example .env
At minimum, set:
APP_ENV=production
APP_DEBUG=false
APP_URL=https://your-domain.com
2

Configure the database

Contacts DB ships with SQLite as the default for local development. In production, switch to MySQL or PostgreSQL:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=contacts_db
DB_USERNAME=db_user
DB_PASSWORD=secure_password
Create the database and the user before running migrations.
3

Configure the mail driver

The default MAIL_MAILER=log writes mail to log files. Replace it with a real transport for production:
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailprovider.com
MAIL_PORT=587
MAIL_USERNAME=your@email.com
MAIL_PASSWORD=your_password
MAIL_FROM_ADDRESS=no-reply@your-domain.com
MAIL_FROM_NAME="Contacts DB"
Supported mailers include smtp, mailgun, ses, postmark, and sendmail.
4

Configure the queue connection

The default QUEUE_CONNECTION=database works out of the box once migrations have run. For higher throughput you can switch to Redis:
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
5

Install PHP dependencies

Install only production dependencies and optimize the autoloader:
composer install --optimize-autoloader --no-dev
6

Generate the application key

If the .env file does not yet have an APP_KEY, generate one:
php artisan key:generate
7

Compile frontend assets

Contacts DB uses Vite for frontend assets. Build the production bundle:
npm ci
npm run build
8

Cache configuration, routes, and views

Caching these significantly reduces per-request overhead:
php artisan config:cache
php artisan route:cache
php artisan view:cache
Re-run these commands after every deployment that changes configuration, routes, or Blade templates.
9

Run database migrations

Apply all pending migrations with the --force flag (required in production to bypass the confirmation prompt):
php artisan migrate --force
10

Seed the admin user

Create the initial admin account using the seeder:
php artisan db:seed --class=AdminUserSeeder
Run this only once on a fresh database. Subsequent deployments should not re-run seeders unless you specifically need to reset seed data.
11

Create the storage symlink

Make uploaded files publicly accessible:
php artisan storage:link
12

Set directory permissions

The web server user (typically www-data) must be able to write to two directories:
chown -R www-data:www-data storage bootstrap/cache
chmod -R 775 storage bootstrap/cache

Environment variables summary

A minimal production .env looks like this:
APP_ENV=production
APP_DEBUG=false
APP_URL=https://your-domain.com

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=contacts_db
DB_USERNAME=db_user
DB_PASSWORD=secure_password

MAIL_MAILER=smtp
QUEUE_CONNECTION=database

FILESYSTEM_DISK=local
SESSION_DRIVER=database
CACHE_STORE=database
Adjust MAIL_*, REDIS_*, and AWS_* variables to match your infrastructure.

Queue worker

Contacts DB uses Laravel queues for sending notifications and processing background jobs. You must run at least one queue worker process continuously in production.

Supervisor configuration

Supervisor is the recommended way to keep the queue worker running and restart it automatically on failure. Create a configuration file at /etc/supervisor/conf.d/contacts-db-worker.conf:
[program:contacts-db-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/contacts-db/artisan queue:work --sleep=3 --tries=3
directory=/var/www/contacts-db
autostart=true
autorestart=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/contacts-db-worker.log
After creating the file, reload Supervisor:
supervisorctl reread
supervisorctl update
supervisorctl start contacts-db-worker:*
After every deployment, restart the worker so it picks up the latest code:
supervisorctl restart contacts-db-worker:*

Task scheduler

Contacts DB schedules background jobs (such as due-soon reminders) using Laravel’s built-in scheduler. Add a single crontab entry that runs every minute:
* * * * * cd /var/www/contacts-db && php artisan schedule:run >> /dev/null 2>&1
Edit the crontab for the web server user:
crontab -u www-data -e
The scheduler itself decides which jobs need to run at any given minute — the crontab entry only needs to fire once per minute.

Web server (Nginx)

Point Nginx at the public/ directory. Below is a minimal configuration for a standard HTTP server block. Add an SSL block via Certbot or your certificate provider for HTTPS:
server {
    listen 80;
    server_name your-domain.com;
    root /var/www/contacts-db/public;
    index index.php;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    charset utf-8;

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

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}
Replace php8.3-fpm.sock with the socket path for the PHP-FPM version installed on your server. After editing, test and reload Nginx:
nginx -t
systemctl reload nginx
The composer run dev script (defined in composer.json) starts a multi-process development environment using concurrently — running php artisan serve, queue:listen, pail, and Vite’s dev server together. Never use composer run dev in production. Use a proper web server (Nginx + PHP-FPM), a Supervisor-managed queue worker, and the compiled Vite assets from npm run build.

Post-deployment verification

After completing all steps, verify the deployment is healthy:
# Check that the application returns a 200 response
curl -o /dev/null -s -w "%{http_code}" https://your-domain.com

# Confirm the queue worker is running
supervisorctl status contacts-db-worker:*

# Confirm the scheduler is registered
php artisan schedule:list

# Tail the application log for errors
tail -f storage/logs/laravel.log

Build docs developers (and LLMs) love