How to install Laravel on a VPS with Debian
To begin the installation, you must have:
- A server with Debian 11 Operating System.
- Access to the server with a user with permissions to install and update packages.
Install apache
apt-get install apache2 -y
You can verify the installation with the following command:
apache2ctl -v
# result
Server version: Apache/2.4.48 (Debian)
Install PHP and other required extensions
apt-get install apt-transport-https gnupg2 ca-certificates -y
Then, we add the necessary repository to install php 8.0:
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
sh -c 'echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
Then we update the repository and install php and other extensions:
apt-get update -y
apt-get install libapache2-mod-php php php-common php-xml php-gd php8.0-opcache php-mbstring php-tokenizer php-json php-bcmath php-zip php-curl unzip curl -y php-mysql
We verify that php has installed correctly:
php --version
# result
PHP 8.0.11 (cli) (built: Sep 23 2021 22:04:05) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.11, Copyright (c) Zend Technologies
with Zend OPcache v8.0.11, Copyright (c), by Zend Technologies
Now we proceed to edit the php.ini
file.
nano /etc/php/8.0/apache2/php.ini
We remove the semicolon from the following extensions to enable them:
- extension=pdo_mysql
Install composer
Now we will install composer to be able to add the laravel dependencies.
curl -sS https://getcomposer.org/installer | php
# result
All settings correct for using Composer
Downloading...
Composer (version 2.1.6) successfully installed to: /root/composer.phar
Use it: php composer.phar
Now we will move the file to the OS binaries so that we can execute it directly:
mv composer.phar /usr/local/bin/composer
We verify the installation:
composer --version
# result
Composer version 2.1.6 2021-08-19 17:11:08
Install mysql/mariadb
We proceed to install mariadb as the database engine. In the terminal:
apt install mariadb-server
# result
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
galera-4 gawk libconfig-inifiles-perl libdbi-perl libmariadb3 libmpfr6 libsigsegv2 libsnappy1v5 mariadb-client-10.5 mariadb-client-core-10.5 mariadb-common
...
We can verify the installed version with the following command:
mariadb --version
# result
mariadb Ver 15.1 Distrib 10.5.11-MariaDB, for debian-linux-gnu (x86_64) using
We verify the service status:
systemctl status mariadb
# result
● mariadb.service - MariaDB 10.5.11 database server
Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2021-08-17 23:38:11 CEST; 21min ago
Docs: man:mariadbd(8)
https://mariadb.com/kb/en/library/systemd/
...
If for some reason the database is not running, start it with the command:
systemctl start mariadb
Now we run the mariadb console as root
to create a new database user:
mysql -u root -p
# result
password:
# Press ENTER as we have not set a password for the root user.
We create a new user, in this case we call it codalas
since it will be the user intended to access the database of the system.
create user codalas@localhost identified by 'password';
We give it all privileges:
GRANT ALL PRIVILEGES ON *.* TO 'codalas'@localhost IDENTIFIED BY 'password';
We update the database privileges:
FLUSH PRIVILEGES;
Warning
For production systems it is recommended to give only the necessary privileges.
Now we create the database that we will use for the system:
CREATE DATABASE laravel;
Create a non-root user to manage the application (if one does not already exist)
In the operating system console, we will create a non-root user, for example called codalas
, using the following command:
adduser codalas
We fill in the information requested such as password, name, etc. The objective of creating a non-root user is to be able to install the laravel dependencies securely.
Install git (optional)
We install git depending on the environment to be able to clone and keep the project up to date with changes during the development stage.
We update the OS package index:
sudo apt update
We install git:
sudo apt install git
We verify the installation:
git --version
# result
git version 2.30.2
Assuming the project was cloned to the /var/www/html/
folder, we will use laravel
as an example folder, we proceed to manage the permissions of the folders:
We add the non-root user to the www-data
user group of the server. This is in order to be able to execute commands within the project without interfering with the ownership permissions that the server needs over the vendor
, storage
and bootstrap
folders.
usermod -a -G www-data codalas
Then we change the ownership of all files in the project folder to codalas
with the www-data
group:
cd html
chown -R codalas:www-data laravel
We update the permissions of the folders:
chmod -R 775 laravel
Once we complete this, we can proceed to perform the rest of the functions with the newly created user. This can be logging in with the new user or from the root
user, executing commands on behalf of the non-root user.
As the root user, we can execute commands on behalf of the created user using:
sudo -u codalas bash
This will start a terminal as the codalas
user.
We proceed to create the file with the environment variables:
We create an .env
file with the following information:
APP_NAME="Laravel"
APP_ENV=local
APP_DEBUG=true
APP_URL=https://localhost
APP_KEY=
LOG_CHANNEL=stack
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=codalas
DB_PASSWORD=password
MAIL_MAILER=smtp
MAIL_FROM_ADDRESS=
MAIL_FROM_NAME=
MAIL_HOST=
MAIL_PORT=587
MAIL_ENCRYPTION=tls
MAIL_USERNAME=
MAIL_PASSWORD=
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DRIVER=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
Install system dependencies
We run composer install
to install the system dependencies.
composer install
# result
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Package operations: 117 installs, 0 updates, 0 removals
- Installing doctrine/inflector (2.0.3): Extracting archive
- Installing doctrine/lexer (1.2.1): Extracting archive
- Installing symfony/polyfill-ctype (v1.23.0): Extracting archive
- Installing webmozart/assert (1.10.0): Extracting archive
- Installing dragonmantank/cron-expression (v3.1.0): Extracting archive
- Installing symfony/polyfill-php80 (v1.23.1): Extracting archive
- Installing symfony/polyfill-mbstring (v1.23.1): Extracting archive
...
Refresh the configuration
We proceed to refresh the application cache:
php artisan config:cache
# result
Configuration cache cleared!
Configuration cached successfully!
php artisan route:cache
# result
Route cache cleared!
Routes cached successfully!
php artisan view:cache
# result
Compiled views cleared!
Blade templates cached successfully!
Migrations
We run the migrations to create the tables in the database:
php artisan migrate
Configure apache
Using the root
user, we will create a virtual host
configuration for the application.
We create a new configuration file for laravel
:
nano /etc/apache2/sites-available/laravel.conf
We modify the file with the following content:
<VirtualHost *:80>
ServerName http://localhost
ServerAdmin example@example.com
DocumentRoot /var/www/html/laravel/public
<Directory /var/www/html/laravel>
Options +Indexes +MultiViews
AllowOverride None
Require all granted
</Directory>
<Directory /var/www/html/laravel/public>
Options +Indexes +MultiViews
AllowOverride None
Require all granted
<IfModule mod_rewrite.c>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Tip
Update the ServerName
, ServerAdmin
, DocumentRoot
and Directory
properties according to the server configuration.
We check that the configuration is correct:
apachectl configtest
# result
Syntax OK
We enable the created virtual host and the rewrite module:
a2enmod rewrite
a2ensite laravel.conf
Tip
The console will indicate that you must restart the server after each command for it to take effect. You can restart the server after executing both.
We restart the server:
systemctl restart apache2
Configure firewall
By default, the server only has port 22 open, which is used for ssh connection. Since the application runs on port 80, we must open it so that the application is externally accessible.
We verify the firewall status:
ufw status
# result
Status: active
To Action From
-- ------ ----
22 ALLOW Anywhere
We enable port 80:
ufw allow 80
If we check the status again, the new port should be shown:
ufw status
# Result
Status: active
To Action From
-- ------ ----
22 ALLOW Anywhere
80 ALLOW Anywhere
80 (v6) ALLOW Anywhere (v6)
Final steps
Then, execute the following commands in the root of the project to update the permissions of the folders.
sudo chown -R codalas:www-data storage
sudo chmod 775 -R storage
We generate the unique identifier used to generate authentication tokens.
php artisan key:generate
We refresh the application configuration.
php artisan config:cache
# result
Configuration cache cleared!
Configuration cached successfully!
php artisan route:cache
# result
Route cache cleared!
Routes cached successfully!
php artisan view:cache
# result
Compiled views cleared!
Blade templates cached successfully!
We access the server address on port 80, either by IP or if it has a URL assigned. Example http://localhost