Installation Guide
This guide walks you through installing Tenanto on your server or local development environment.
Requirements
Server Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| PHP | 8.3 | 8.4 |
| PostgreSQL | 16 | 16 |
| Redis | 7 | 7 |
| Node.js | 20 | 22 LTS |
| Composer | 2.x | Latest |
PHP Extensions
bcmath, ctype, curl, dom, fileinfo, hash, json,
mbstring, openssl, pcre, pdo, pdo_pgsql, session,
tokenizer, xml, redis, zip
Installation Methods
Method 1: Docker (Recommended)
Docker provides the easiest setup with all services pre-configured.
Step 1: Extract the Package
unzip tenanto-v1.0.0.zip -d /path/to/your/projects/
cd /path/to/your/projects/tenanto
Step 2: Configure Environment
cp .env.example .env
Edit .env with your settings:
APP_NAME="Your SaaS Name"
APP_URL=https://yourdomain.com
# Database (Docker defaults work out of the box)
DB_CONNECTION=pgsql
DB_HOST=db
DB_PORT=5432
DB_DATABASE=tenanto
DB_USERNAME=tenanto
DB_PASSWORD=secret
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
Step 3: Start Docker
docker compose up -d
This starts 8 services:
- app - PHP-FPM application
- nginx - Web server (ports 80, 443)
- db - PostgreSQL database
- redis - Cache and queue
- queue - Background job worker
- scheduler - Laravel scheduler
- mailhog - Local email inbox
- vite - Vite dev server
Step 4: Install Dependencies
docker compose exec app composer install
No
npm installon the host. Theviteservice runsnpm ciautomatically in its own container on first start and serves frontend assets with hot module replacement athttp://localhost:5273. Changes to.blade.php,resources/css/*andresources/js/*reload instantly. If port 5273 clashes with another project on your machine, setVITE_HOST_PORT=5274(or any free port) in.envbeforedocker compose up -d.
Step 5: Initialize Application
docker compose exec app php artisan key:generate
docker compose exec app php artisan migrate --seed
Step 6: Configure DNS (hosts file)
Tenanto uses tenanto.local and per-tenant subdomains by default (configured in .env.example via TENANCY_CENTRAL_DOMAINS=tenanto.local,admin.tenanto.local). Your local machine has to resolve those names to 127.0.0.1, which means adding entries to your operating system's hosts file.
Required entries:
127.0.0.1 tenanto.local
127.0.0.1 admin.tenanto.local
127.0.0.1 demo.tenanto.local
You can add more lines for any additional tenants you create, e.g. 127.0.0.1 acme.tenanto.local.
Linux / macOS — open a terminal and edit /etc/hosts with sudo:
sudo nano /etc/hosts
# or: sudo vi /etc/hosts
Append the three lines, save, exit. No restart needed.
Windows 10/11 — hosts file lives at C:\Windows\System32\drivers\etc\hosts. You must open your text editor as Administrator (right-click Notepad → "Run as administrator"), then File → Open → paste the path → change file filter to "All Files" → select hosts. Append the three lines, save. If Notepad refuses to save, your editor was not launched with elevated privileges.
WSL2 users — edit the Windows hosts file (the path above), not /etc/hosts inside WSL. WSL2 inherits DNS resolution from Windows for *.local names.
Verify the entries took effect:
# Linux/macOS/WSL2:
getent hosts tenanto.local admin.tenanto.local demo.tenanto.local
# Windows PowerShell:
Resolve-DnsName tenanto.local -Type A
All three names should resolve to 127.0.0.1.
Production note: When you deploy to a real domain, replace
tenanto.localeverywhere - in.env(APP_URL,TENANCY_CENTRAL_DOMAINS,TENANCY_SUBDOMAIN_SUFFIX) and in your DNS records. The hosts file step is only needed for local development.
Method 2: Traditional Server
Step 1: Clone/Upload Files
Upload the extracted files to your server's web root.
Step 2: Install Dependencies
composer install --optimize-autoloader --no-dev
npm ci && npm run build
Production builds only. Traditional (non-Docker) server deployments compile assets once with
npm run build- the generatedpublic/build/directory is served by nginx. The Dockerviteservice is not used in production; seedocker-compose.prod.yml.
Step 3: Configure Environment
cp .env.example .env
php artisan key:generate
Edit .env:
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
DB_CONNECTION=pgsql
DB_HOST=localhost
DB_PORT=5432
DB_DATABASE=tenanto
DB_USERNAME=your_db_user
DB_PASSWORD=your_db_password
REDIS_HOST=localhost
Step 4: Database Setup
php artisan migrate --seed
Step 5: Web Server Configuration
Nginx:
server {
listen 80;
server_name yourdomain.com *.yourdomain.com;
root /var/www/tenanto/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}
Step 6: Permissions
chmod -R 775 storage bootstrap/cache
chown -R www-data:www-data storage bootstrap/cache
Step 7: Queue Worker & Scheduler
Supervisor (queue):
[program:tenanto-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/tenanto/artisan queue:work redis --sleep=3 --tries=3
autostart=true
autorestart=true
user=www-data
numprocs=2
Cron (scheduler):
* * * * * cd /var/www/tenanto && php artisan schedule:run >> /dev/null 2>&1
Post-Installation
1. Access the Application
After completing the install steps above, three local URLs are available:
| Panel | URL |
|---|---|
| Marketing landing | http://tenanto.local |
| System Admin Panel | http://admin.tenanto.local/admin |
| Tenant Panel (demo tenant) | http://demo.tenanto.local/app |
| Mailhog (test inbox) | http://localhost:8025 |
If any of these URLs returns "site cannot be reached", revisit Step 6 above - your hosts file is missing entries.
2. Default Login Credentials
The seeder creates four accounts using the password from the DEMO_DEFAULT_PASSWORD environment variable. With the unmodified .env.example, that value is ChangeMe-DemoPass!.
System Admin (use at http://admin.tenanto.local/admin):
| Password | |
|---|---|
[email protected] |
ChangeMe-DemoPass! |
Tenant Panel (use at http://demo.tenanto.local/app):
| Role | Password | |
|---|---|---|
[email protected] |
Owner | ChangeMe-DemoPass! |
[email protected] |
Admin | ChangeMe-DemoPass! |
[email protected] |
Member | ChangeMe-DemoPass! |
Important - rotate the password before going public.
ChangeMe-DemoPass!is the same string for every fresh install of this package. Change it in two ways:
- Before first seed: edit
DEMO_DEFAULT_PASSWORDin.env, then runphp artisan migrate --seed. New users get the new password.- After seeding: edit
DEMO_DEFAULT_PASSWORDin.env, then runphp artisan demo:reset-passwords. The command rotates the four demo accounts in place. Or manually change passwords through the admin panel.

3. Create Your First Tenant
Log into the admin panel, then go to Tenants → New tenant. Pick a slug like acme, save, then add 127.0.0.1 acme.tenanto.local to your hosts file (same place as Step 6 above) so the new subdomain resolves locally. The new tenant becomes accessible at http://acme.tenanto.local/app.

4. Configure Stripe (Optional)
See Billing Setup for Stripe configuration.
Troubleshooting
Docker containers won't start
# Check Docker is running
docker info
# Check for port conflicts
netstat -tulpn | grep -E '80|443|5432'
# View logs
docker compose logs -f
"Class not found" errors
composer dump-autoload
php artisan config:clear
php artisan cache:clear
php artisan view:clear
Database connection refused
- Docker: Use
dbas host, notlocalhost - Check PostgreSQL is running:
docker compose ps - Verify credentials in
.env
Permissions errors
chmod -R 775 storage bootstrap/cache
# Docker:
docker compose exec app chmod -R 775 storage bootstrap/cache
Next Steps
- Admin Panel Guide - Managing tenants and users
- Tenant Panel Guide - Using the tenant admin
- Billing Setup - Configure Stripe integration