Caption: ViserHotel Laravel hotel booking and reservation platform.
Introduction
I wanted rooms, rates, and a booking form on a server I control. ViserHotel (CodeCanyon) is a Laravel hotel booking app: public site, admin dashboard, payment gateways in the package. I installed it on Ubuntu 22.04 with Apache, PHP 8.1, MySQL, Composer, and Node for assets.
I do not have a cute story about a boutique hotel client. This is the same lab path as any CodeCanyon Laravel zip: unpack, .env, key:generate, migrate, npm run build, document root public/. On a fresh Ubuntu box this install is famous for a blank page when APP_KEY is still the placeholder, and a 500 when storage/ is not writable by the web user.
Where it broke
1. Blank page — APP_KEY never generated
On a fresh Ubuntu box this is the failure this install is famous for. You copied .env from the zip, left APP_KEY=base64:GENERATED_KEY, opened the domain, white screen.
No application encryption key has been specified.
Fix already in this post:
php artisan key:generate
Then reload. If you still see white, check storage/logs/laravel.log.
2. 500 — permissions on storage/ and .env
Zip extracted as root. Apache/PHP-FPM is www-data.
failed to open stream: Permission denied
sudo chown -R www-data:www-data /var/www/viserhotel
sudo chmod -R 755 /var/www/viserhotel
If logs still fail, tighten write bits on Laravel’s writable dirs the usual way: storage and bootstrap/cache need to be writable (775 is the pattern I use on other Laravel apps in this series). I am not inventing a ViserHotel-only flag.
Assets 404 after a “successful” install is usually npm run build never run, not a missing PHP extension.
Prerequisites
- OS: Ubuntu 22.04 LTS (this write-up). Windows/IIS exists; I did not use it here.
- Web server: Apache or Nginx. Apache vhost is below.
- PHP: 8.1 or higher
- Database: MySQL/MariaDB
- Composer
- Node.js and npm (front-end build)
- Git if you track updates that way
- Domain and SSL for anything public
Hardware: 2 CPU / 4 GB RAM / 20 GB disk minimum. 4 CPU / 8 GB / SSD is more comfortable if you generate PDFs or run reports.
The zip comes from your CodeCanyon download. I cannot wget a pirated copy; you upload viserhotel.zip yourself.
Step 1: Update the server
sudo apt update && sudo apt upgrade -y
Step 2: PHP and extensions
sudo apt install php8.1 php8.1-cli php8.1-mysql php8.1-xml php8.1-mbstring php8.1-curl php8.1-zip unzip curl git -y
Missing php-xml is the usual Laravel “Class DOMDocument not found” wall. This apt line already includes php8.1-xml. If the installer or artisan fatals on DOM/XML, reinstall that package and restart Apache/FPM.
You will also want a web SAPI. On Ubuntu that is typically libapache2-mod-php8.1 or PHP-FPM plus an Apache proxy. This post’s vhost assumes Apache can run PHP for public/index.php. Install the Apache PHP module if php CLI works but the browser downloads index.php:
sudo apt install apache2 libapache2-mod-php8.1 -y
sudo a2enmod rewrite
I am not adding extra PHP flags beyond what this app’s original steps listed.
Step 3: Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --version
If the zip did not include vendor/, run composer install --no-dev --optimize-autoloader in the project root. If Composer OOMs on a 1 GB VPS, COMPOSER_MEMORY_LIMIT=-1 composer install is the documented Laravel workaround — same as Bagisto on a small box.
Step 4: MySQL
sudo apt install mysql-server -y
sudo mysql_secure_installation
CREATE DATABASE viserhotel;
CREATE USER 'viseruser'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT ALL PRIVILEGES ON viserhotel.* TO 'viseruser'@'localhost';
FLUSH PRIVILEGES;
Step 5: Unpack ViserHotel
Upload the CodeCanyon zip, then:
unzip viserhotel.zip -d /var/www/viserhotel
Some zips nest a folder. If you see /var/www/viserhotel/viserhotel/public, move up so public/ is directly under /var/www/viserhotel.
sudo chown -R www-data:www-data /var/www/viserhotel
sudo chmod -R 755 /var/www/viserhotel
Step 6: .env
APP_NAME="ViserHotel"
APP_ENV=production
APP_KEY=base64:GENERATED_KEY
APP_DEBUG=false
APP_URL=https://yourdomain.com
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=viserhotel
DB_USERNAME=viseruser
DB_PASSWORD=StrongPassword123!
php artisan key:generate
That command overwrites the placeholder. APP_URL must match the hostname you type in the browser (http vs https).
Step 7: Migrate and seed
php artisan migrate --seed
Run this as a user who can write storage/ — after chown, sudo -u www-data php artisan migrate --seed avoids root-owned cache files. I am not inventing extra artisan flags; --seed is what this post already used.
If migrate complains about missing tables or a lock, the zip’s README may want an import of an .sql dump instead. Follow the file you paid for. I will not invent a --force you do not have in that PDF.
Step 8: Node assets
sudo apt install nodejs npm -y
npm install
npm run build
If CSS/JS 404, run npm run build again from the project root, and confirm Apache’s document root is public/, not the folder that contains package.json.
Step 9: Apache
<VirtualHost *:80>
ServerName yourdomain.com
DocumentRoot /var/www/viserhotel/public
<Directory /var/www/viserhotel/public>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/viserhotel_error.log
CustomLog ${APACHE_LOG_DIR}/viserhotel_access.log combined
</VirtualHost>
AllowOverride All so Laravel’s public/.htaccess can rewrite to index.php. Without mod_rewrite, you get 404 on every booking URL.
sudo a2ensite viserhotel.conf
sudo systemctl reload apache2
Put the vhost in /etc/apache2/sites-available/viserhotel.conf before a2ensite.
Step 10: TLS
sudo apt install certbot python3-certbot-apache -y
sudo certbot --apache -d yourdomain.com
Then set APP_URL=https://yourdomain.com and php artisan config:clear.
Step 11: Open the app
https://yourdomain.com
Admin is usually:
https://yourdomain.com/admin
If the vendor shipped different admin credentials in the documentation, use those and change them immediately. I will not invent a default password.
Extra tips
ViserHotel is Laravel. The CodeCanyon “install” PDF often stops at unzip and URL. Operators still need:
- Laravel —
.env,APP_KEY,artisan migrate,storage/+bootstrap/cacheownership,public/as the web root. Blank page and 500 are this layer. - Composer vendor — if the zip is source-style,
composer installis required. If vendor is bundled, skip it. - Node build —
npm install/npm run buildfor the theme. Missing mix/vite output looks like “the template is broken.” - Scheduler / queues — many CodeCanyon Laravel apps send mail and reminders via
schedule:runorqueue:work. If the vendor README mentions cron, add:
* * * * * cd /var/www/viserhotel && php artisan schedule:run >> /dev/null 2>&1
I only add a queue worker if their .env has QUEUE_CONNECTION other than sync. I am not inventing Horizon or Spatie for this product.
Troubleshooting
- 500: permissions and
.env.storage/logs/laravel.log. - Database connection: user/password/host in
.env, thenphp artisan config:clear. - Assets not loading:
npm run buildagain; document rootpublic/. - Blank page:
php artisan key:generate. - XML/DOM errors:
php8.1-xmlinstalled and Apache restarted. - Rewrite 404:
a2enmod rewrite,AllowOverride All.
Screenshots and images
Cover image is the product visual I already had for this post. I did not scrape extra admin screenshots from the vendor demo.
A feature I would not have found from the homepage
The CodeCanyon zip is a Laravel app with a vendor PDF. The PDF often says “upload and visit /install.” This write-up used artisan migrate --seed because that is what the original post documented. If your zip still has a web installer, use that and still set APP_KEY, APP_URL, and public/ as the vhost root. Do not run both and hope.
Admin URL and seed users live in the vendor docs, not in a blog post I will invent. Change whatever default admin they shipped before the hostname is public. APP_DEBUG=false.
Payment gateways are .env plus admin settings, not a Composer package I would guess at. I would get a room type and a test booking with “offline/cash” (or whatever they ship) working before Stripe keys go in. Mail for booking confirmations is the same Laravel mail/QUEUE_CONNECTION story as Invoice Ninja: if they queued it, you need a worker or cron.
cPanel vs VPS: on cPanel the document root still has to be public/, or you fight index.php in a subdirectory. I deploy these on cPanel often enough that I check that first when someone pastes a screenshot of a directory listing.
Day two on the VPS
CodeCanyon Laravel apps age like any other Laravel app:
- Vendor updates come as a new zip. I would diff
.env, keepstorage/, and read their upgrade notes. I would notcomposer updateblindly and assume the theme still compiles. - Cron: if booking reminders exist, add
schedule:runforwww-data. Confirm with a log line, not hope. - Mail: a booking with no email is a support ticket. Test SMTP after
APP_KEYand permissions, not before. - Backups:
viserhoteldatabase plusstorage/(uploads, generated invoices if they store files). - PHP 8.1 vs 8.3: this post used 8.1 because that is what the original install listed. If the vendor now wants 8.2+, I would follow their current PDF, not invent flags. Same extensions:
xml,mbstring,curl,zip,mysql. - UFW and TLS before the first real guest. Admin at
/adminis a brute-force target.
I would add rooms and a test booking on HTTPS, then payment keys. Kubernetes is not a day-two task for a 20-room property.
References
- Laravel documentation
- Composer
- ViserHotel on CodeCanyon: search for ViserHotel Ultimate Hotel Booking Solution (item you purchased)
- Certbot
Conclusion
ViserHotel is unpacked on my Ubuntu box: MySQL database, .env with a real APP_KEY, migrate --seed, npm run build, Apache to public/. The front end loads; /admin is next. I would then set room types and rates, plug in the payment gateway the vendor documented, turn on TLS, and add a mysqldump cron. I would not talk about Kubernetes until a real booking has hit the database.
Did you hit the same wall?
I got stuck on a blank page after php artisan migrate --seed because APP_KEY was still the placeholder and storage/ was not writable by the web user. Did you hit the same thing, or a different one — Composer memory, storage permissions, PHP extensions, a queue worker that never started? Tell me in the comments. I read them.
Need this done on your server?
I deploy and harden Laravel/CodeCanyon apps on cPanel or VPS, and offer monthly Server Watch retainers. Hire for deploy · Care plan