Ubuntu LAMP setup for Laravel

Nav • May 15, 2020

ubuntu

If you need a local server for testing, or want to set up a production server, below are the step-by-step instructions on how to install a Ubuntu server. The focus will be on setting up a LAMP stack to host Laravel sites. We'll configure OpenSSH, Firewall, MySQL, PHP, and mount a network shared drive.

Install server

You have a few options for installing a local server. VMware Fusion or Workstation and Oracle VirtualBox are popular choices. On the cloud you have many choices such as Digital Ocean, AWS, Google to name a few.

If you choose to use the cloud, you don't need to install it manually, you can skip to the Login using SSH section.

If a local server is the way you're going, then download Ubuntu Server version from Ubuntu directly. ubuntu.com/download/server.

Do a fresh install. There's not much you need to worry about with the install. Most default settings will do.

If you're setting up a static IP, you may need help with configuring it. Use this link to calculate IP if required: subnet-calculator.com/cidr.php

Login using SSH

On a fresh install of Ubuntu server, you are able to login using SSH. So from your terminal type:

ssh username@serverip

Then enter the password you chose during installation.

Set root user password

By default, Ubuntu does not allow you to set a root password during install. I personally like to have access to the root user, so it's the first thing I change. Log into the server, and switch to root user.

sudo -i

Enter your password. Then to set the root password:

passwd

Network setup

If you need to make adjustments to your network settings, the file is located here:

sudo pico /etc/netplan/50-cloud-init.yaml

Below is a sample of what this file should look like. Credit

# This file is generated from information provided by
# the datasource.  Changes to it will not persist across an instance.
# To disable cloud-init's network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        enp0s3:
            dhcp4: false
            addresses: [192.168.1.202/24]
            gateway4: 192.168.1.1
            nameservers:
              addresses: [8.8.8.8,8.8.4.4,192.168.1.1]
    version: 2

I usually have multiple network cards, some for internal communication and some for external. Some are hardwired directly to equipment, so depending on your needs, it can get pretty complicated. If you're having any issues with setting up a static IP, there is a reference article here. Link

Server IP

If you need to verify the server IP, paste the command below.

curl http://icanhazip.com

Update server

Update the server to the latest patches. There's always a few security packages that should be added.

sudo apt update
sudo apt upgrade

SSH

Next, secure up SSH. We want to turn off authentication via password, and login through SSH keys.

On your mac, just open a new terminal window and run:

ssh-keygen

I usually keep defaults, and skip the passphrase. This will generate two files in your ~/.ssh folder. id_rsa and id_rsa.pub. Copy the contents of id_rsa.pub.

Now add the key to your Ubuntu server. Navigate to your home folder. Then type:

mkdir .ssh
cd .ssh
sudo pico authorized_keys

Then paste your key.

Depending on how you plan on logging in, either using your username (recommended) or root, you can paste the keys under the appropriate user folder.

If the above gives you any issues, there are a few other ways to get your key on to the server. Checkout Digital Ocean's docs.

Disable password authentication

By turning off the password authentication, you will only be able to login using the ssh keys. Personally, I setup all my servers with this method. Passwords are so insecure, and a pain to remember.

Edit the OpenSSH config file.

sudo pico /etc/ssh/sshd_config

Add the following to the bottom of the file. It's up to you if you want to allow root to login remotely. Some will say it's not a secure thing to do, and they are correct. So omit PermitRootLogin yes if you dont want root login.

PasswordAuthentication no
PermitRootLogin yes

Restart ssh server.

sudo systemctl restart ssh

Firewall

Check the firewall status, it should show as disabled.

sudo ufw status

You can also list the applications available to add to your firewall rules.

sudo ufw app list

Add OpenSSH. There are two ways to do this, one you can allow the application privileges, and the second way is to open ports.

sudo ufw allow "OpenSSH"
sudo ufw enable

A few helpful tools

ifconfig does not come pre-installed anymore. Alternatively, you can also use ip a.

sudo apt install net-tools

Also, let's just make sure these are installed.

sudo apt install -y git curl wget zip unzip

Install Apache

sudo apt install apache2

Enable rewrite mod, and restart Apache

sudo a2enmod rewrite
sudo systemctl restart apache2

Update firewall to allow http & https communication.

sudo ufw allow in "Apache Full"

Installing MySQL

sudo apt install mysql-server

Let's secure up mysql.

sudo mysql_secure_installation

### VALIDATE PASSWORD COMPONENT - N
### Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
### Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
### Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
### Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y

In case you need it, the config file is located at:

/etc/mysql/mysql.conf.d/mysqld.cnf

Give root user access to login remotely, at least to tunnel login. Most SQL clients will allow you to tunnel in via SSH and login to your MySQL. It's much better this way as you don't need to open firewall ports, etc.

sudo mysql

Create a root user access. This is optional. I prefer to tunnel in and have access to all the databases on the server.

CREATE USER 'root'@'%' IDENTIFIED BY 'someawesomesecurepassword';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
exit

To give an application or developer access to a specific database, I prefer this method. If I know multiple people are working on one server it's best to keep access separated.

CREATE DATABASE client_database;
CREATE USER 'dev_username'@'%' IDENTIFIED WITH mysql_native_password BY 'SuperSecurePassword!';
GRANT alter,create,delete,drop,index,insert,select,update,trigger,alter routine,create routine, execute,references, create temporary tables on client_database.* to 'dev_username';
FLUSH PRIVILEGES;
exit

If you ever need to update the user's password:

ALTER USER 'dev_username'@'%' IDENTIFIED BY 'NewSuperPa55!';

MySLQ remote login

Using a SQL client, to login remotely as root, there is one other setting that needs to be changed. We need to change the way the root user is authenticated.

sudo mysql -u root
USE mysql;
SELECT User, Host, plugin FROM mysql.user;

As you can see in the query, the root user is using the auth_socket plugin

You may get errors trying to login. The way to solve this is you can set the root user to use the mysql_native_password plugin.

sudo mysql -u root

USE mysql;
UPDATE user SET plugin='mysql_native_password' WHERE User='root';
FLUSH PRIVILEGES;
exit;

Restart mysql

sudo systemctl restart mysql

Just a note, by default, root @ localhost password is blank.

Install php 7.4

sudo apt install php7.4 libapache2-mod-php

Ensure php extensions are all installed. This is probably overkill, but remove the ones you don't need.

sudo apt install php7.4-mysql php7.4-common php7.4-bcmath openssl php7.4-json php7.4-mbstring php7.4-dom php7.4-zip php7.4-soap

Move index.php to the top of the list.

sudo pico /etc/apache2/mods-enabled/dir.conf

Test PHP installation.

sudo pico /var/www/html/info.php

Paste this in the file, and save.

<?php
phpinfo();
?>

Now visit the website to check your php installation.

http://your-ip/info.php

Install Composer

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

Make Composer executable.

sudo chmod +x /usr/local/bin/composer

Do a version check.

composer --version

Optional - mount a network windows server hard drive

If you have a shared folder that you need to access from your Ubuntu machine, this should help. In my case, I usually need to mount an Indesign server output folder.

mkdir /mnt/idscc
sudo pico /etc/fstab

Add this line. This will give you full read/write access, as long as the account allows it.

Now this is not the most secure method of mounting the hard drive. You are entering passwords in plain text. There are better ways to do this if security is an issue.

//192.168.0.100/wwwroot       /mnt/idscc      cifs    vers=1.0,username=Administrator,password=SomeSecurePassword!,file_mode=0777,dir_mode=0777,iocharset=utf8,sec=ntlm 0 0

Mount the drive.

mount -a

SSH key on your Ubuntu server

If you need to add the server's ssh key to a provider, another server, etc., run:

ssh-keygen

Clone your Laravel site, make the folder is writable.

chmod -R 777 storage
chmod -R 777 bootstrap

Apache site

Make a virtual host.

sudo pico /etc/apache2/sites-available/navcodes.dev.conf

Customize the code below and paste into the .conf file.

<VirtualHost *:80>
    ServerName navcodes.dev:80
    DocumentRoot "/var/www/navcodes/public"

    <Directory "/var/www/navcodes/public">
        AllowOverride all
        LimitRequestBody 0
        Options Indexes FollowSymLinks MultiViews
        Order allow,deny
        allow from all
        Require all granted
    </Directory>

RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]

RewriteCond %{SERVER_NAME} =navcodes.dev
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

Activate site.

sudo a2ensite navcodes.dev.conf

Restart Apache.

sudo systemctl restart apache2

Encrypt

Install certbot on server. Follow the instruction on certbot. https://certbot.eff.org.