This guide was created with the idea that you should visit less than countless pages online in order to spin up a fast NGINX/PHP server Droplet on Digital Ocean. It makes an effort at explaing what you are doing every step of the way and WITHOUT extra words, advertisement or anything that may keep you from objectively understanding what the hell it is that you are doing. This is version 1 and it will be revised towards less and less text until it can't be any smaller.
You can buy a domain name from Google Domains starting at $9/year and spin up an Ubuntu Server 20.04(LTS) Digital Ocean Droplet starting at $5/month.
Minimum initital investment of $14.00.
Minimum recurring investment of $9/year & $5.00/month.
We will not be covering https as it would call for elements that are beyond the scope of this guide. Once you are finished you may run a test at securityheaders.com to visualize how far you've come and whatelse you can do in NGINX by editing the config file (more on this later).
Most of the content is in the format Acquire/Create, Install/Configure, Use/Maintain.
gmail.com - Admin Email service provider. This is our parent admin email account. All three cloud services below are subscribed to using this Gmail parent admin account.
domains.google - Domain service provider and DNS Management tool. We are going to use our Gmail account to acquire domain names from here and manage everything about them here as well.
Configuring DNS Settings - A Record
Configuring DNS Settings - CNAME Record
digitalocean.com - Droplet and Managed Database Cluster service provider. We are going to use our Gmail account to sign-up for Digital Ocean and then use the control panel to create a project that will contain our Ubuntu OS Droplet (VPS).
Managed Databases will later be added to this Digital Ocean project as well.
About Droplets (Ubuntu OS)
About Managed Databases (MySQL)
In the Digital Ocean control panel, every service you add must belong to a Project. You first create a project, then you add services to it. Some of the services you may add include Droplets (The Operating System) & Database Clusters (Managed MySQL Database).
Remember! Domains (DNS Management) is once again done through Google Domains.
1. Login to Digital Ocean.
2. On the top left, click + New Project.
3. Enter the project Name (example1.com), Description and Purpose.
4. Click Create Project
Now that an empty Project has been created, we can begin to add services to it. The first service we will add is an Ubuntu Server 20.04(LTS) Droplet.
The operating system we are going to use is Ubuntu Server 20.04(LTS). This version of Linux receives frequent updates and has a big community around to help you with questions. This is ideal for developers.
In this step, we will be adding a Ubuntu Server 20.04(LTS) Operating System which Digital Ocean offers as a Droplet.
1. Login to Digital Ocean.
2. On the left, select the project you have created.
3. On the main page, select Create a Droplet.
1. Choose an image -> Ubuntu 20.04(LTS) x64
2. Choose a plan -> Starter @ $5.00/mo - 1GB/1CPU - 25GB SSD - 1000GB TRANSFER
3. Add block storage -> Not applicable
4. Choose a datacenter region - > New York, San Francisco, Amsterdam, Singapore, London, Frankfurt, Toronto, Bangalore
5. Select additional options -> Not applicable
6. Authentication -> One time password
7. Finalize and create
- How many Droplets? -> 1
- Choose a hostname -> ubuntu-s-1vcpu-1gb-sfo2-01
8. Add tags -> Optional
9. Select Project -> example1.com
10. Click Create Droplet.
When this Droplet is created, it will literally contain nothing more than the Operating system. It will also be assigned a public IP address which is visible when you have the project selected in the control panel.
More specifically, Projects > example1.com > Resources > Droplets > example1.com
We are now ready to begin Ubuntu's initial setup which involves creating a system user with sudo privileges that we will use for system administration later on.
The sudo
prefix helps enforce best practices, running only commands that need to be run as root (such as software installation commands) without leaving you at a root shell where you may stay logged in or run other applications as root.
When you log in as your own user account, programs you run are restricted from writing to the rest of the system – they can only write to your home folder. You can’t modify system files without gaining root permissions. This helps keep your server secure.
When you first create a new Ubuntu 20.04(LTS) server, there are a few configuration steps that you should take early on as part of the basic setup. This will increase the security and usability of your server and will give you a solid foundation for subsequent actions.
Available in Linux and Windows, this command is used to start the SSH client program that enables secure connection to the SSH server on a remote machine. The `ssh` command is used from logging into the remote machine, transferring files between the two machines, and for executing commands on the remote machine.
1. To login to your Droplet, open up the command prompt CMD (Windows) or BASH (Linux) and type:
ssh root@droplet_ip_address
In the above snippet, droplet_ip_address
is replaced with your Digital Ocean project assigned public IP address.
Accept the warning about host authenticity if it appears. If you are using password authentication, provide your root password to log in.
The root user is the administrative user in a Linux environment that has very broad privileges.
Because of the heightened privileges of the root account, you are discouraged from using it on a regular basis. This is because part of the power inherent with the root account is the ability to make very destructive changes, even by accident.
Also, everything installed by root is only allowed to be used by root. This is why we only use root to create users; nothing more.
The next step is to set up an alternative user account with a reduced scope of influence for day-to-day work. You’ll learn how to gain increased privileges during the times when you need them.
Once you are logged in as root, we’re prepared to add the new user account that we will use to log in from now on.
This example creates a new user called user1
, but you should replace it with a username that you like:
adduser user1
2. You will be asked a few questions, starting with the account password.
3. Enter a strong password and, optionally, fill in any of the additional information if you would like. This is not required and you can just hit ENTER in any field you wish to skip.
Now, we have a new user account with regular account privileges. However, we may sometimes need to do administrative tasks.
To avoid having to log out of our normal user and log back in as the root account, we can set up what is known as "superuser" or root privileges for our normal account. This will allow our normal user to run commands with administrative privileges by entering the prefix sudo
before each command.
To add these privileges to our new user, we need to add the new user to the sudo
group. By default, on Ubuntu 20.04(LTS), users who belong to the sudo
group are allowed to use the sudo
command.
As root, run this command to add your new user to the sudo group (substitute the highlighted word with your new user):
usermod -aG sudo user1
user1
is now part of the sudo
group and will now inherit its privileges.
Lastly, we remove Ubuntu's default firewall -- ufw
, to avoid conflict.
This is because we are going to use firewalld
and there is only place for one firewall in an Operating System.
To remove and completely purge ufw without confirmation, type:
apt remove --purge ufw -y
To change root
account password, type:
sudo passwd root
To disable root
account , type:
sudo passwd -dl root
From this point forward, we exit
the terminal and log back in as a sudo user. Now, when logged in as user1, you can type sudo
before commands to perform actions with superuser privileges.
Every important command typed by user1
is now preceded by the keyword sudo
(superuser privileges).
You might already know that Ubuntu is derived from Debian Linux. And Debian uses dpkg
packaging system.
A packaging system is a way to provide programs and applications for installation. This way, you don’t have to build a program from the source code which, trust me, is not a pretty way to handle packages.
APT (Advanced Package Tool) is the command line tool to interact with the packaging system. There is already dpkg
commands to manage it. But APT is a more friendly way to handle packaging. You can use it to find and install new packages, upgrade packages, remove the packages etc.
apt
commands provide a command line way to interact with APT and manage packages.
In this step, we cover the relevant apt commands used in this guide.
Updating the package database requires superuser privileges so you’ll need to use sudo
.
sudo apt update
When you run this command, you’ll see the package information being retrieved from various servers.
You’ll see three types of lines here, Hit
, Get
and Ign
. Basically these are:
Hit
: there is no change in package version from the previous version
Get
: There is a new version available. It will download the information about the version (not the package itself). You can see that there is download information (size in kb) with the ‘get’ line in the screenshot above.
Ign
: the package is being ignored. Either the package is way too recent that it doesn’t even bother to check or there was an error in retrieving the file but error was trivial and thus it is being ignored. Don’t worry, this is not an error.
Upgrade installed packages with apt
Once you have updated the package database, you can now upgrade the installed packages. The most convenient way is to upgrade all the packages that have available updates.
To upgrade the installed packages, type:
sudo apt upgrade
This will show you how many and which all packages are going to be upgraded.
There is another way to provide a complete upgrade by using the command below:
sudo apt full-upgrade
sudo apt full-upgrade
works the same as sudo apt upgrade
except that if system upgrade needs the removal of a package already installed on the system, it will do that. Whereas, the normal upgrade
command won’t do this.
apt update vs apt upgrade
Though it sounds like when you do an sudo apt update
, it will update the packages and you’ll get the latest version of the package. But that’s not true. sudo apt update
only updates the database of the packages.
For example, if you have XYZ package version 1.3 installed, after sudo apt update
, the database will be aware that a newer version 1.4 is available. When you do sudo apt upgrade
after sudo apt update
, it upgrades (or updates, whichever term you prefer) the installed packages to the newer version.
This is the reason why the fastest and the most convenient way to update Ubuntu system by using this command:
sudo apt update && sudo apt upgrade -y
To list installed packages, type:
sudo apt list --installed
To search for a package, type:
sudo apt search package_name_here
To show more about a package before installing or removing it, type:
sudo apt show package_name_here
To install a package without confirmation, type:
sudo apt install package_name_here -y
To remove libs and packages that were installed automatically to satisfy the dependencies of an installed package, type:
sudo apt autoremove
To remove and completely purge a package without confirmation, type:
sudo apt remove --purge package_name_here -y
Installation
In this step, we will be adding firewalld 0.8.2-1 to our Ubuntu Droplet.
Firewalls provide a basic level of security for your server. These applications are responsible for denying traffic to every port on your server, except for those ports/services you have explicitly approved. Linux Redhat has a service called firewalld
to perform this function. A tool called sudo firewalld-cmd
is used to configure firewalld
firewall policies.
1. To install firewalld
without confirmation, type:
sudo apt install firewalld -y
2. To enable firewalld
to start on system boot, type:
sudo systemctl enable firewalld
3. To start firewalld
service, type:
sudo systemctl start firewalld
4. Check status of the service to make sure it started:
sudo systemctl status firewalld
5. To Restart the service, type:
sudo systemctl restart firewalld
6. To Confirm the service is running, type:
sudo firewall-cmd --state
Note that firewalld
it is both active and enabled, meaning it will start by default if the server is rebooted.
sudo apt show package_name_here
Now that the service is up and running, we can use the firewalld-cmd
command to get and set policy information for the firewall.
7. First let’s list which services are already *permanently* allowed:
sudo firewall-cmd --permanent --list-all
To get a list of all services that can be enabled by name, type:
sudo firewall-cmd --get-services
To add a service that should be allowed, use the --add-service
flag:
sudo firewall-cmd --add-service=http --permanent
The --permanent
option means persist rules against server reboots.
This would add the http
service and allow incoming TCP traffic to port 80.
Enable http & https
8. To enable both http
and https
on a single line, type:
sudo firewall-cmd --add-service={http,https} --permanent
9. The configuration will update after you reload the firewall:
sudo firewall-cmd --reload
ALWAYS reload firewalld
after making changes to the configuration.
The FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features (mostly) useful for heavy-load sites. PHP-FPM has two major portion of configuration and also uses php.ini
to load PHP configuration.
Global Directives (php-fpm.conf) & Pool Directives (default is www.conf
, you can name it site you site's purpose eg. blog.conf, forum.conf, etc.)
Notice that the apt
package manager recognizes php-fpm
as the install keyword but after installation, Ubuntu recognizes it by php7.4-fpm
instead. Yeah. You're welcome.
Installation
In this step, we will be adding php7.4-fpm to our Ubuntu Droplet.
1. To install php-fpm
without confirmation, type:
sudo apt install php-fpm -y
Also install php-curl
& php-mysql
modules without confirmation:
sudo apt install php-curl -y
sudo apt install php-mysql -y
The two PHP modules listed above are required if you are going to use PHP PDO to communicate with your Digital Ocean Managed MySQL Database.
Next, we uncomment the following 3 lines in php.ini
file to make php7.4-fpm
aware that the modules we've just installed are to be used.
To edit php.ini
, type:
sudo nano /etc/php/7.4/fpm/php.ini
Uncomment the following extensions:
;extension=curl
;extension=mysqli
;extension=pdo_mysql
After uncommenting, remember to save the php.ini
file by pressing Ctrl + O to Save, Enter and Ctrl + X to return to the command prompt.
2. To enable php7.4-fpm
to start on system boot, type:
sudo systemctl enable php7.4-fpm
3. To start php7.4-fpm
service, type:
sudo systemctl start php7.4-fpm
4. Check status of the service to make sure it started:
sudo systemctl status php7.4-fpm
5. To Restart the service, type:
sudo systemctl restart php7.4-fpm
The PHP-FPM process manager is configured out of the box for the most part. To use it, simply start the process and you are ready to go.
php-fpm.conf
1. To list php processes and find the location of php-fpm.conf
file, type:
sudo ps aux | grep php
Command description:
ps
= process status
a
= show processes for all users
u
= display the process's user/owner
x
= also show processes not attached to a terminal
| grep php
= filter by keyword "php"
The command output should contain the path to php-fpm.conf
file.
/etc/php/7.4/fpm/php-fpm.conf
Next we navigate to this file in order to find the unix socket file path php7.4-fpm.conf
is using to accept incoming requests after it was installed.
2. To open the php-fpm.conf
file, type:
sudo nano /etc/php/7.4/fpm/php-fpm.conf
At the end of the php-fpm.conf
file, you should find the following line:
include = /etc/php/7.4/fpm/pool.d/*.conf
This means our PHP-FPM process manager is using configurations from the /pool.d/
directory.
www.conf
By default, php-fpm
places a single file called www.conf
inside the /pool.d/
directory described above.
This file is then loaded every time the php7.4-fpm
service is started.
To open the www.conf
file, type:
sudo nano /etc/php/7.4/fpm/pool.d/www.conf
When viewing the www.conf
file, you can see that the php7.4-fpm
(process manager) is using a UNIX socket file to accept incoming PHP script requests.
The address on which to accept FastCGI requests:
listen = /run/php/php7.4-fpm.sock
We will use this path & file name /run/php/php7.4-fpm.sock
in the fastcgi_pass
directive of an NGINX location block so that nginx
handles all the HTML pages while php7.4-fpm
handles all the PHP pages; coming up next, in web server setup guide.
ALWAYS reload php7.4-fpm
after making changes to php.ini
file.
Installation
In this step, we will be adding nginx 1.18.0 to our Ubuntu Droplet.
1. To Show public IP address, type:
curl ifconfig.co
2. To install nginx
without confirmation, type:
sudo apt install nginx -y
3. To enable nginx
to start on system boot, type:
sudo systemctl enable nginx
4. To start nginx
service, type:
sudo systemctl start nginx
5. Check status of the service to make sure it started:
sudo systemctl status nginx
6. To restart the service, type:
sudo systemctl restart nginx
nginx.conf
The nginx.conf
file is loaded by nginx
during startup and contains all of the directives required to run the server.
By default, nginx
places the nginx.conf
configuration file in the following directory:
/etc/nginx/nginx.conf
7. To open the nginx.conf
file, type:
sudo nano /etc/nginx/nginx.conf
About the default nginx.conf
file...
The default nginx.conf
file is basic, for serving static files only and security at this point is non-existing.
Since we are not setting up an https server, we will replace the default configuration file with a more secure version. This is as close to secure as I can get you, using NGINX as an http-protocol only server.
Below is the nginx.conf
file we are going to use instead.
ALWAYS reload nginx
after making changes to nginx.conf
file.
The nginx templates below achieve an A score @ securityheaders.com WITHOUT USING HTTPS. To achieve an A+ score, you have to use https header Strict-Transport-Security
which is again part of an HTTPS implementation and not covered in this guide.
Download it. Look at it. Break it. And learn it.
1. Download template nginx.conf
, type:
sudo curl -o /etc/nginx/nginx.conf https://www.npo.run/v1/templates/nginx.file
2. Download template fastcgi.conf
, type:
sudo curl -o /etc/nginx/fastcgi.conf https://www.npo.run/v1/templates/fastcgi.file
View nginx.conf
View fastcgi.conf
After downloading config files to their locations, we create the site root and download the templates. Finally we test nginx.conf
then restart
OR reload
nginx.
3. To create the site root used in the nginx.conf
file, type:
sudo mkdir -p /var/www/example1.com/public
4. To download the index template index.html
, type:
sudo curl -o /var/www/example1.com/public/index.html https://www.npo.run/v1/templates/index.file
5. To download the nginx logo for index.html
, logo.png
, type:
sudo curl -o /var/www/example1.com/public/logo.png https://www.npo.run/v1/templates/logo.file
6. To download the nginx favicon, favicon.ico
, type:
sudo curl -o /var/www/example1.com/public/favicon.ico https://www.npo.run/v1/templates/favicon.file
7. To download custom error pages http-error.tar
compressed directory to your /home
directory for extraction, type:
sudo curl -o /home/http-error.tar https://www.npo.run/v1/templates/http-error.file
7.1 To extract downloaded http-error.tar
directory to your site root /var/www/example1.com/public
directory, type:
sudo tar xf /home/http-error.tar -C /var/www/example1.com/public
7.2 To remove downloaded http-error.tar
file from your /home
directory after extraction, type:
sudo rm -f /home/http-error.tar
7.3 To replace the absolute path for the nginx logo.png found inside each error page html file now located in the /http-error
directory, type:
sudo sed -i 's/example1.com/example2.com/g' /var/www/example1.com/public/http-error/*.html
In the snipet above we loop through each html file inside the recently extracted /http-error
directory, find the string example1.com
and replace it with the string example2.com
where example2.com is the domain name you are going to be using; that you actually own.
7.4 To rename the physical directory of your site to match/reflect this update:
sudo mv -T /var/www/example1.com /var/www/example2.com
7.5 To update nginx.conf
to match/reflect this update:
sudo sed -i 's/example1.com/example2.com/g' /etc/nginx/nginx.conf
8. To test the nginx.conf
file before restart
OR reload
, type:
sudo nginx -t
9. To restart the service, type:
sudo systemctl restart nginx
9.1 OR To reload nginx.conf
WITHOUT RESTARTING the service, type:
sudo systemctl reload nginx
At this point we have nginx
& php7.4-fpm
online and ready to accept incoming requests.
To Show Digital Ocean Dropet public IP address, type:
curl ifconfig.co
To Visit your Digital Ocean Dropet, open up your browser and go to:
http://droplet_ip_address
http://droplet_ip_address
After acquiring a domain from Google Domains, you need to point it to your http://droplet_ip_address
.
Login to your Google Domains Control Panel, click on Get a new domain and follow the steps.
1. Once you have purchased a domain it will appear under the My domains tab.
2. Click on your domain to arrive at the Domain overview tab.
3. Click the DNS tab.
4. Scroll to the Custom resource records section.
5. To add an A Record select A from the drop down box to enter your droplet_ip_address
.
5. To add a CNAME Record select CNAME from the drop down box to enter your example1.com
.
While Google is quite fast at doing this, it may take some time for your domain DNS records to propagate through the internet.
You may use DNS Checker to verify your domain name has fully propagated.
Commands available for user account management, basic file and directory operations, file viewing commands, manage and monitor system, basic networking commands.
To login to your Droplet, open up the command prompt CMD (Windows) or BASH (Linux) and type:
ssh root@droplet_ip_address
To list all nginx
access.log files, type:
ls /var/log/nginx/access.*
To truncate all nginx
access.log files, type:
sudo truncate /var/log/nginx/access.* --size 0
To delete all nginx
access.log files, type:
sudo rm -f /var/log/nginx/access.*
To list all nginx
error.log files, type:
ls /var/log/nginx/error.*
To truncate all nginx
error.log files, type:
sudo truncate /var/log/nginx/error.* --size 0
To delete all nginx
error.log files, type:
sudo rm -f /var/log/nginx/error.*