Finally! After all those preparations, we can see our project working in our browser.
Usually, NginX and PHP-FPM service runs as www-data user and it is a system user for services.
In the best case scenario, we would like to isolate our web project from any system services and maybe have a different directory for example /home/web/demoproject
as opposed to /var/www/html
where you need root user explicitly.
adduser web
command as root. You will be prompted to define a password for a web user add fill in optional details. Make sure to choose a secure password.root@ip-172-31-44-101:~# adduser webAdding user `web' ...Adding new group `web' (1001) ...Adding new user `web' (1001) with group `web' ...Creating home directory `/home/web' ...Copying files from `/etc/skel' ...New password:Retype new password:passwd: password updated successfullyChanging the user information for webEnter the new value, or press ENTER for the default Full Name []: Room Number []: Work Phone []: Home Phone []: Other []:Is the information correct? [Y/n] Y
web
user and create a structure for how we want our future laravel project served.We can easily do that by entering sudo su web
or just su web
if you're a root. The user you're currently logged in as can be seen in your command prompt or optionally can be checked with the whoami
command.
ubuntu@ip-172-31-44-101:~$ sudo su webweb@ip-172-31-44-101:/home/ubuntu$ whoamiweb
Navigate to your home directory, this can be done by entering cd
without any parameters or cd ~
or cd /home/web
. The present working directory can be checked with the pwd
command.
web@ip-172-31-44-101:/home/ubuntu$ cdweb@ip-172-31-44-101:~$ pwd/home/web
Now create a new directory for our demo project:
web@ip-172-31-44-101:~$ mkdir demoproject
And for this step, we just create a single PHP file to test future configurations.
web@ip-172-31-44-101:~$ cd demoproject/web@ip-172-31-44-101:~/demoproject$ nano index.php
Here are the contents of our index.php
file for now.
<?php echo 'test';
Then press CTRL-X to save and exit the editor.
Currently, NginX and PHP-FPM would have no access to our /home/web
directory, and we need a few more things to do for NginX to be able to serve and process this php file.
www-data
group. Current present groups our new users are in can be checked with the groups web
command.root@ip-172-31-44-101:~# groups webweb : web
To add our user to the www-data
group. we can use the usermod
command with -aG
flags.
root@ip-172-31-44-101:~# usermod -aG www-data web
And then check groups again.
root@ip-172-31-44-101:~# groups webweb : web www-data
As we can see, the user has been added to the www-data group.
/home/web
folder permissions to allow services to read it using the chmod 755 /home/web
command.web@ip-172-31-44-101:~$ chmod 755 /home/web
root@ip-172-31-44-101:/home/web# nano /etc/nginx/sites-enabled/default
Lines that we are interested in are near each other starting with root /var/www/html
It should be the 41st and 44th lines, they look like that:
root /var/www/html; # Add index.php to the list if you are using PHPindex index.html index.htm index.nginx-debian.html;
Change root directive root /var/www/html
to root /home/web/demoproject
.
And as you have guessed the comment suggests we need to append index.php to the index directive:
Update index index.html index.htm index.nginx-debian.html;
to index index.html index.htm index.nginx-debian.html index.php;
.
The result should look like that:
root /home/web/demoproject; # Add index.php to the list if you are using PHPindex index.html index.htm index.nginx-debian.html index.php;
Full NginX default site configuration without comments looks like this:
server { listen 80 default_server; listen [::]:80 default_server; root /home/web/demoproject; index index.html index.htm index.nginx-debian.html index.php; server_name _; location / { try_files $uri $uri/ =404; } location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; }}
For sake of simplicity, we won't go deeper into NginX configuration nuances.
/etc/php/8.1/fpm/pool.d
.root@ip-172-31-44-101:~# nano /etc/php/8.1/fpm/pool.d/www.conf
In the [www]
section find lines user = www-data
and group = www-data
, they should not be too far from the beginning.
From
user = www-datagroup = www-data
update it to
user = webgroup = web
And exit by saving the file with CTRL-X.
systemctl
command from previous chapters.root@ip-172-31-44-101:~# systemctl restart nginxroot@ip-172-31-44-101:~# systemctl restart php8.1-fpm
If you navigate to your site URL http://<YOUR-SERVER-IP-ADDRESS>
you should see the site echoing test
to confirm the configuration of services is successful.
/home/web/demoproject
directory. The simplest form would be to download your Laravel project archive on the server and extract it to the /home/web/demoproject
directory or pull it from the GIT repository.We will cover how to pull it from your GitHub repository by using the git clone
command.
Since we will be cloning the existing repository we can delete the existing demoproject
directory, because it will be created when we clone the Laravel project.
web@ip-172-31-44-101:~$ rm -fr demoproject/
To be able to clone
the repository and later pull
from it using the ssh method we need to generate a new ssh-key pair.
Note: even if the repository is public, you need to add your ssh key otherwise access would be denied.
Note: If you wish to clone the public repository you do not own, we suggest skipping a key generation and using the HTTPS method. For example, to copy the demo project we used in this tutorial, use
git clone https://github.com/mc0de/rds-ec2-project.git demoproject
and proceed to step 10.
To generate new ssh-key pair use the ssh-keygen
command.
web@ip-172-31-44-101:~$ ssh-keygen -t ed25519 -C "your_email@example.com"Generating public/private ed25519 key pair.Enter file in which to save the key (/home/web/.ssh/id_ed25519):Enter passphrase (empty for no passphrase):Enter same passphrase again:Your identification has been saved in /home/web/.ssh/id_ed25519Your public key has been saved in /home/web/.ssh/id_ed25519.pubThe key fingerprint is:SHA256:/B0X+6/9X83V+PXvXGTIVYUTSPUjNSp8PMwBC+rvwvU your_email@example.comThe key's randomart image is:+--[ED25519 256]--+| . oo+o=+|| . o * *.o|| . + O.oo|| .. o.o*o|| .S . * *|| .o . o *=|| . ..o . O|| o. E o=|| .. .o@|+----[SHA256]-----+
Your public key can be previewed using this command:
web@ip-172-31-44-101:~$ cat /home/web/.ssh/id_ed25519.pub
Now copy this key, go to your account settings on GitHub https://github.com/settings/keys and add it by pressing the [New SSH Key]
button
Fill in the form and submit it by pressing [Add SSH key]
.
Now go to your repository and copy the SSH URL:
And clone the repository:
web@ip-172-31-44-101:~$ git clone git@github.com:mc0de/rds-ec2-project.git demoprojectCloning into 'demoproject'...remote: Enumerating objects: 173, done.remote: Counting objects: 100% (173/173), done.remote: Compressing objects: 100% (130/130), done.remote: Total 173 (delta 26), reused 173 (delta 26), pack-reused 0Receiving objects: 100% (173/173), 119.98 KiB | 706.00 KiB/s, done.Resolving deltas: 100% (26/26), done.
The last argument of the git clone git@github.com:mc0de/rds-ec2-project.git demoproject
command is the directory where it should be stored otherwise it will use the GitHub repository name which is not always ideal.
index.php
in its root directory. So we need to update our NginX configuration once again. According to Official Documentation https://laravel.com/docs/9.x/deployment#nginx our configuration now should look like that:root@ip-172-31-44-101:~# nano /etc/nginx/sites-enabled/default
server { listen 80 default_server; listen [::]:80 default_server; root /home/web/demoproject/public; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff"; index index.php; charset utf-8; server_name _; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; }}
As we see our document root is now /home/web/demoproject/public
, index directive has only an index.php
value because this is the only entry point the Laravel application has and a bunch of other settings. More information on various configurations can be found on Official NginX Documentation https://www.nginx.com/resources/wiki/start/#pre-canned-configurations.
Navigate to your project directory:
web@ip-172-31-44-101:~$ cd demoproject/
Copy .env.example
to .env
web@ip-172-31-44-101:~/demoproject$ cp .env.example .env
Fill in your database credentials in the .env
file when we were settings the RDS instance in the previous chapter.
web@ip-172-31-44-101:~/demoproject$ nano .env
DB_HOST=database-1.cbd1u2cfua0q.eu-central-1.rds.amazonaws.comDB_DATABASE=demo_projectDB_USERNAME=demo_userDB_PASSWORD=******
Run composer install
web@ip-172-31-44-101:~/demoproject$ composer installInstalling dependencies from lock file (including require-dev)Verifying lock file contents can be installed on current platform.Package operations: 108 installs, 0 updates, 0 removalsAs there is no 'unzip' nor '7z' command installed zip files are being unpacked using the PHP zip extension.This may cause invalid reports of corrupted archives. Besides, any UNIX permissions (e.g. executable) defined in the archives will be lost.Installing 'unzip' or '7z' may remediate them. - Downloading doctrine/inflector (2.0.6) - Downloading doctrine/lexer (1.2.3)<...> INFO Discovering packages. laravel/breeze .............................................................................................................................. DONE laravel/sail ................................................................................................................................ DONE laravel/sanctum ............................................................................................................................. DONE laravel/tinker .............................................................................................................................. DONE nesbot/carbon ............................................................................................................................... DONE nunomaduro/collision ........................................................................................................................ DONE nunomaduro/termwind ......................................................................................................................... DONE spatie/laravel-ignition ..................................................................................................................... DONE 81 packages you are using are looking for funding.Use the `composer fund` command to find out more!
Run php artisan key:generate
web@ip-172-31-44-101:~/demoproject$ php artisan key:generate INFO Application key set successfully.
Run php artisan storage:link
to make necessary symlinks for accessing files in public storage
web@ip-172-31-44-101:~/demoproject$ php artisan storage:link INFO The [public/storage] link has been connected to [storage/app/public].
Run migrations using php artisan migrate
web@ip-172-31-44-101:~/demoproject$ php artisan migrate INFO Preparing database. Creating migration table ............................................................................................................... 58ms DONE INFO Running migrations. 2014_10_12_000000_create_users_table ................................................................................................... 78ms DONE 2014_10_12_100000_create_password_resets_table ......................................................................................... 34ms DONE 2019_08_19_000000_create_failed_jobs_table ............................................................................................. 40ms DONE 2019_12_14_000001_create_personal_access_tokens_table .................................................................................. 62ms DONE
Login to server:
$ ssh -i ~/.ssh/ec2-demo-web-ubuntu-server.pem ubuntu@ubuntu-aws
Login as a web
user:
ubuntu@ip-172-31-44-101:~$ sudo su web
Navigate to your project's directory:
web@ip-172-31-44-101:/home/ubuntu$ cd /home/web/demoproject/
Issue git pull
command:
web@ip-172-31-44-101:~/demoproject$ git pullremote: Enumerating objects: 12, done.remote: Counting objects: 100% (12/12), done.remote: Compressing objects: 100% (6/6), done.remote: Total 9 (delta 3), reused 9 (delta 3), pack-reused 0Unpacking objects: 100% (9/9), 54.81 KiB | 597.00 KiB/s, done.From github.com:mc0de/rds-ec2-project 901ecc4..50ae9b6 main -> origin/mainUpdating 901ecc4..50ae9b6Fast-forward .gitignore | 1 - public/build/assets/app.73cd3409.css | 1 + public/build/assets/app.d426e523.js | 32 ++++++++++++++++++++++++++++++++ public/build/manifest.json | 12 ++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 public/build/assets/app.73cd3409.css create mode 100644 public/build/assets/app.d426e523.js create mode 100644 public/build/manifest.json
http://<YOUR-SERVER-IP-ADDRESS>
is very hard to memorize and not convenient at all. You may purchase a domain name on one of the providers and add DNS A type record with the value of your public IP address.On your domain provider's panel entry should be similar to this:
A aws-course.laraveldaily.com 18.195.117.231 # your actual server ip address
or if you don't use a subdomain it even may look similar to that, using @
instead of name:
A @ 18.195.117.231
Configuration used in this tutorial doesn't need any additional changes on the server to support the domain name, all HTTP requests will resolve to the default site.
Congratulations, you've completed this "Deploy Laravel to AWS" course!
Our demo project used in this tutorial with all exact configurations can be accessed at aws-course.laraveldaily.com