Documentation Developer Guide Installation Guide

Installation Guide

This guide covers everything required to install Online Casino Script on your own infrastructure. Two paths are documented: Docker (recommended for development and simple production deployments) and manual bare-metal (for operators running their own Ubuntu 22.04 server).


Table of Contents

  1. Server Requirements
  2. Option A — Docker Setup
  3. Option B — Manual Installation (Ubuntu 22.04)
  4. Environment Configuration
  5. Database Setup and Migrations
  6. SSL Certificate
  7. Systemd Services (Horizon + Reverb)
  8. Cron Schedule
  9. File Permissions
  10. Health Check and Smoke Tests
  11. Subsequent Deploys
  12. Troubleshooting Common Install Errors

1. Server Requirements

Docker (development / simple production)

Requirement Minimum
Docker Desktop 4.0+ (includes Compose v2)
Git Any recent version
make Pre-installed on macOS/Linux; Windows: use Git Bash or WSL
RAM 4 GB available to Docker

Bare-metal production server

Hardware

Resource Minimum (500 concurrent players) Recommended (5,000 concurrent players)
CPU 4 vCPUs 8 vCPUs
RAM 8 GB 16 GB
Disk 50 GB SSD 100 GB NVMe SSD
Bandwidth 100 Mbps 1 Gbps
OS Ubuntu 22.04 LTS Ubuntu 22.04 LTS

Software versions

Software Minimum version
PHP 8.3+
Nginx 1.24+
MySQL 8.0+ (or MariaDB 10.6+)
Redis 7.0+
Node.js 20+ (build step only)
Composer 2+
Certbot Latest

Required PHP extensions

bcmath curl fileinfo gd mbstring pdo_mysql openssl pcntl redis tokenizer xml zip


2. Option A — Docker Setup

This is the fastest path. No PHP, MySQL, or Redis installation required — everything runs in containers.

Clone the repository

git clone <your-repo-url> casino
cd casino

Run the one-command setup

make setup

This single command:

  • Copies .env.docker.env (pre-configured for Docker networking)
  • Builds all Docker images
  • Starts all services: app, nginx, mysql, redis, horizon, reverb, scheduler
  • Generates APP_KEY and JWT_SECRET
  • Runs all database migrations
  • Seeds default admin account, games, and demo data

Expected output:

[setup] Copying .env.docker → .env
[setup] Building images...
[setup] Starting services...
[setup] Waiting for database...
[setup] Running migrations...
[setup] Seeding database...
[setup] Done! Visit http://localhost

The first run downloads base images — this takes 3–10 minutes depending on connection speed. Subsequent starts take seconds.

Verify the install

URL What you should see
http://localhost Player-facing casino lobby
http://localhost/admin Admin login page
http://localhost/health JSON health status — all "ok"

Daily Docker workflow

make up          # Start all services
make down        # Stop all services
make dev         # Start with Vite hot reload (development)
make logs        # Tail all container logs
make logs-app    # Tail only app container logs
make shell       # Open a bash shell inside the app container
make ps          # Show running container status

Database commands

make migrate     # Run pending migrations
make seed        # Re-run seeders
make fresh       # Drop all tables, re-migrate, re-seed (prompts for confirmation — destructive)

Updating to a new version (Docker)

git pull
make down && make up
make migrate

3. Option B — Manual Installation (Ubuntu 22.04)

Use this path for production bare-metal deployments.

Step 1 — Install system dependencies

# Update the system
sudo apt update && sudo apt upgrade -y

# Add PHP 8.3 repository
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update

# Install PHP 8.3 and all required extensions
sudo apt install -y php8.3-fpm php8.3-cli php8.3-mysql php8.3-redis 
    php8.3-bcmath php8.3-curl php8.3-fileinfo php8.3-gd php8.3-mbstring 
    php8.3-openssl php8.3-pcntl php8.3-tokenizer php8.3-xml php8.3-zip

# Install Nginx
sudo apt install -y nginx

# Install MySQL 8
sudo apt install -y mysql-server
sudo mysql_secure_installation

# Install Redis 7
sudo apt install -y redis-server

# Install Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

# Install Node.js 20 (build step only)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# Install Certbot (for SSL)
sudo apt install -y certbot python3-certbot-nginx

Step 2 — Deploy the application

# Create application directory
sudo mkdir -p /var/www/casino
sudo chown -R www-data:www-data /var/www/casino

# Clone the repository
cd /var/www/casino
git clone <your-repo-url> . --depth=1

# Install PHP dependencies (production — no dev packages)
composer install --no-dev --optimize-autoloader

# Install Node dependencies and build frontend assets
npm ci
npm run build

Step 3 — Configure Nginx

Save the following as /etc/nginx/sites-available/casino:

upstream php-fpm {
    server unix:/run/php/php8.3-fpm.sock;
}

# Redirect HTTP → HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

# Main HTTPS server block
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;

    root /var/www/casino/public;
    index index.php;

    # SSL — managed by Certbot (see Section 6)
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include             /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam         /etc/letsencrypt/ssl-dhparams.pem;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Gzip compression
    gzip on;
    gzip_types text/plain text/css application/json application/javascript
               text/xml application/xml image/svg+xml;

    # Max upload size for KYC documents
    client_max_body_size 10M;

    # Laravel SPA entry point
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # PHP handling
    location ~ .php$ {
        fastcgi_pass php-fpm;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_read_timeout 60;
    }

    # WebSocket proxy — Laravel Reverb
    location /app/ {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400;
    }

    # Static asset caching (Vite generates content-hashed filenames)
    location /build/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # Deny access to hidden and sensitive files
    location ~ /. { deny all; }
    location ~ .(env|log|htaccess)$ { deny all; }
}

Enable the site:

sudo ln -s /etc/nginx/sites-available/casino /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

Step 4 — Configure PHP-FPM

Create a dedicated pool at /etc/php/8.3/fpm/pool.d/casino.conf:

[casino]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500

php_value[memory_limit] = 256M
php_value[max_execution_time] = 60
php_value[upload_max_filesize] = 10M
php_value[post_max_size] = 12M

; OPcache (critical for performance)
php_admin_value[opcache.enable] = 1
php_admin_value[opcache.memory_consumption] = 256
php_admin_value[opcache.max_accelerated_files] = 20000
php_admin_value[opcache.validate_timestamps] = 0
sudo systemctl restart php8.3-fpm

4. Environment Configuration

Create and edit .env

cp .env.example .env

Open .env and set at minimum:

# Application
APP_NAME="Your Casino Name"
APP_ENV=production
APP_URL=https://example.com
APP_DEBUG=false
FORCE_HTTPS=true

# Database
DB_HOST=127.0.0.1
DB_DATABASE=online_casino
DB_USERNAME=casino
DB_PASSWORD=strong-password-here

# Redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=your-redis-password
REDIS_PORT=6379

# Mail
MAIL_MAILER=smtp
MAIL_HOST=smtp.your-provider.com
MAIL_PORT=587
MAIL_USERNAME=your@email.com
MAIL_PASSWORD=your-password
MAIL_FROM_ADDRESS=noreply@example.com
MAIL_FROM_NAME="Your Casino"

# WebSockets
REVERB_APP_KEY=         # openssl rand -hex 16
REVERB_APP_SECRET=      # openssl rand -hex 32
REVERB_HOST=example.com
REVERB_PORT=443
REVERB_SCHEME=https
REVERB_ALLOWED_ORIGINS=https://example.com

For a full reference of every available variable, see the Configuration Reference.

Generate application secrets

# Application encryption key
php artisan key:generate

# JWT secret
php artisan jwt:secret

Cache the configuration

After editing .env, always cache the configuration:

php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache

Important: Run php artisan config:clear && php artisan cache:clear any time you change .env on a server where config is cached.


5. Database Setup and Migrations

Create the database and user

CREATE DATABASE online_casino CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'casino'@'localhost' IDENTIFIED BY 'strong-password-here';
GRANT ALL PRIVILEGES ON online_casino.* TO 'casino'@'localhost';
FLUSH PRIVILEGES;

Configure MySQL for production

Add to /etc/mysql/mysql.conf.d/casino.cnf:

[mysqld]
# InnoDB buffer pool — set to 50–70% of available RAM
innodb_buffer_pool_size = 4G
innodb_log_file_size = 512M

# Financial data requires strict ACID compliance
innodb_flush_log_at_trx_commit = 1
innodb_flush_method = O_DIRECT

max_connections = 300

# Binary log for point-in-time recovery
log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 7
binlog_format = ROW
sudo systemctl restart mysql

Configure Redis for production

Edit /etc/redis/redis.conf:

bind 127.0.0.1
requirepass your-strong-redis-password
maxmemory 2gb
maxmemory-policy allkeys-lru
appendonly yes
appendfsync everysec
sudo systemctl restart redis-server

Run migrations and seed initial data

php artisan migrate --force
php artisan db:seed --force

The seeder creates:

  • Default admin account (admin@casino.com / password) — change immediately
  • All game configurations
  • Default payment method templates
  • Default role permissions
php artisan storage:link

6. SSL Certificate

Use Let’s Encrypt (free) via Certbot:

sudo certbot --nginx -d example.com -d www.example.com

Certbot automatically edits your Nginx config to add the SSL block.

Verify auto-renewal:

sudo certbot renew --dry-run
sudo systemctl status certbot.timer

7. Systemd Services (Horizon + Reverb)

Two long-running processes must be kept alive by systemd.

Laravel Horizon (queue workers)

Save as /etc/systemd/system/casino-horizon.service:

[Unit]
Description=Online Casino Script — Laravel Horizon
After=network.target mysql.service redis.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/casino
ExecStart=/usr/bin/php artisan horizon
Restart=on-failure
RestartSec=5s
KillSignal=SIGTERM
TimeoutStopSec=60

[Install]
WantedBy=multi-user.target

Laravel Reverb (WebSocket server)

Save as /etc/systemd/system/casino-reverb.service:

[Unit]
Description=Online Casino Script — Laravel Reverb WebSocket Server
After=network.target mysql.service redis.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/casino
ExecStart=/usr/bin/php artisan reverb:start --host=127.0.0.1 --port=8080
Restart=on-failure
RestartSec=5s
KillSignal=SIGTERM
TimeoutStopSec=30

[Install]
WantedBy=multi-user.target

Enable and start services

sudo systemctl daemon-reload
sudo systemctl enable casino-horizon casino-reverb
sudo systemctl start casino-horizon casino-reverb

# Verify both are active
sudo systemctl status casino-horizon
sudo systemctl status casino-reverb

8. Cron Schedule

Add to /etc/cron.d/casino:

* * * * * www-data cd /var/www/casino && php artisan schedule:run >> /dev/null 2>&1

The Laravel scheduler manages:

  • Daily ledger balance audit
  • Daily multi-account detection scan
  • Daily bonus abuse detection
  • Daily betting velocity check
  • Queue metrics snapshot every 5 minutes

9. File Permissions

sudo chown -R www-data:www-data /var/www/casino
sudo find /var/www/casino -type f -exec chmod 644 {} ;
sudo find /var/www/casino -type d -exec chmod 755 {} ;
sudo chmod -R 775 /var/www/casino/storage
sudo chmod -R 775 /var/www/casino/bootstrap/cache
sudo chmod 600 /var/www/casino/.env

The .env file must be readable only by the web server user — it contains secrets.


10. Health Check and Smoke Tests

Health endpoint

curl https://example.com/api/health

Expected response when fully healthy:

{
  "status": "ok",
  "database": "ok",
  "redis": "ok",
  "horizon": "ok",
  "timestamp": "2026-01-01T00:00:00Z"
}

Pre-launch checklist

Infrastructure

  • [ ] DNS records pointing to server IP
  • [ ] SSL certificate issued and valid (https://example.com loads without browser warning)
  • [ ] Both systemd services running: casino-horizon and casino-reverb
  • [ ] Cron running: systemctl status cron

Application

  • [ ] All migrations applied: php artisan migrate:status (no pending)
  • [ ] Config cached: php artisan config:cache
  • [ ] Storage symlink created: ls -la public/storage
  • [ ] Frontend assets built: ls public/build/manifest.json

Configuration

  • [ ] Admin password changed (not password)
  • [ ] 2FA enabled on admin account
  • [ ] At least one payment method enabled
  • [ ] At least one game enabled
  • [ ] Email sending tested
  • [ ] APP_DEBUG=false confirmed

Security

  • [ ] Redis requires a password (requirepass in redis.conf)
  • [ ] MySQL user has no SUPER or FILE privileges
  • [ ] Firewall: only ports 80, 443, 22 exposed publicly
  • [ ] SESSION_SECURE_COOKIE=true
  • [ ] .env has chmod 600 permissions

11. Subsequent Deploys

For zero-downtime deploys on bare-metal:

cd /var/www/casino
git pull
composer install --no-dev --optimize-autoloader
npm ci && npm run build
php artisan migrate --force
php artisan config:cache && php artisan route:cache && php artisan view:cache && php artisan event:cache
php artisan horizon:terminate    # Horizon auto-restarts via systemd
sudo systemctl restart php8.3-fpm

12. Troubleshooting Common Install Errors

Connection refused — MySQL not running

sudo systemctl status mysql
sudo systemctl start mysql

Verify your .env values match the MySQL user and database you created.

Connection refused — Redis not running

sudo systemctl status redis-server
redis-cli ping    # Should return PONG

APP_KEY not set / 500 on all requests

php artisan key:generate
php artisan config:clear

JWT Secret not set — login returns 500

php artisan jwt:secret
php artisan config:clear

Missing PHP extension

php -m | grep -E "bcmath|pdo_mysql|redis|gd|fileinfo|zip|mbstring|pcntl"
# Install any that are missing:
sudo apt install -y php8.3-<extension-name>
sudo systemctl restart php8.3-fpm

APP_DEBUG=true throws RuntimeException in production

Set APP_DEBUG=false in .env and clear the config cache.

SESSION_SECURE_COOKIE=true blocks local HTTP login

For local development only: set SESSION_SECURE_COOKIE=false in .env. Never set this to false in production.

WebSocket connection fails after deploy

Ensure REVERB_ALLOWED_ORIGINS in .env includes your domain URL, then restart Reverb:

php artisan config:clear
sudo systemctl restart casino-reverb

500 after deploy — stale config cache

php artisan optimize:clear
php artisan config:cache && php artisan route:cache && php artisan view:cache

Assets returning 404 — blank SPA

Ensure you ran npm run build as part of the deploy. Verify public/build/manifest.json exists.


For a complete reference of all .env variables, see Configuration Reference. For advanced scaling, see the infrastructure guides in docs/infrastructure/.