How to setup a Raspberry Pi web server with Raspbian Stretch Lite, Nginx, MariaDB and PHP as the LEMP stack
When you want to deploy a PHP application that you wrote, you can first deploy it on a Raspberry Pi. Once your PHP application gets enough traction, you can then port it over to a computer with more horsepower.
When your PHP application employs MySQL or MariaDB as the backing database, we can put it up on a LEMP stack. In this situation, HTTP requests will first be directed to the Nginx reverse proxy server. Whenever the request is made to a php application, Nginx will then pass it on to the PHP7 Fast CGI Process Manager (PHP FPM) for generating the HTTP response.
Given these points, this post provides the steps to setup a Raspberry Pi web server with Raspbian Stretch Lite, Nginx, MariaDB and PHP as the LEMP stack.
What do you need to setup a Raspberry Pi web server on a LEMP stack?
Before we dive into the details, let us look at what we need to setup a Raspberry Pi web server on a LEMP stack.
In order to host a dynamic web application on a Raspberry Pi LEMP stack, we will need the following:
- A domain name and the corresponding DNS / DDNS configurations to direct HTTP requests to our Raspberry Pi.
- The Raspberry Pi hardware for your Raspberry Pi web server.
- A copy of Raspbian Stretch Lite installed on a microSD card.
- A Nginx instance running on Raspbian Stretch Lite
- A PHP-FPM (FastCGI Process Manager) running on Raspbian Stretch Lite
- A MariaDB instance running on Raspbian Stretch Lite
- A copy of Certbot to help acquire artefacts to enable browser-trusted HTTPS communication.
Getting a domain name and configuring DNS / DDNS to direct HTTP requests to your Raspberry Pi
Before a user sees your website, he/she will type a domain name on a browser. Given that domain name, the browser then uses the Domain Name System to get an IP address. Once the browser has the IP address, it then sends HTTP requests to your HTTP server and build the web page based on the HTTP responses from the server.
In case you are getting a domain name for your web server on the Internet, you can consider Namecheap.
So why do I recommend Namecheap for hosting a Raspberry Pi Web server at home? This is because, you can get your Raspberry Pi to use Namecheap dynamic DNS to update your domain when your home’s public IP address changes.
When your Raspberry Pi sits behind a router, you will also need to forward port 80 and port 443 of your router to your Raspberry Pi. In case you need a reference, you can follow the tutorial on how to forward port 80 and port 443 on Linksys EA7500 Max-Stream AC1900 router.
Recommended Raspberry Pi hardware for your Raspberry Pi web server
Since the different models of Raspberry Pi does not differ too much in terms of pricing, I recommend Raspberry Pi 3 Model B+ as the board to use. So what can we get to build a Raspberry Pi 3 project like this? In case you need some reference, you can consider the following hardware list to build your Raspberry Pi web server:
- CanaKit Raspberry Pi 3 B+ (B Plus) with 2.5A Power Supply (UL Listed)
- Raspberry Pi 2/3 official case Black/Grey or Raspberry Pi 2/3 official case Red/White
- Sandisk Ultra 64GB Micro SDXC UHS-I Card with Adapter - 100MB/s U1 A1
- AmazonBasics RJ45 Cat-6 Ethernet Patch Cable - 3 Feet (0.9 Meters)
Setting up Raspbian Stretch Lite with SSH server enabled on your microSD card
Once you had gathered all the necessary hardware, proceed to setup Raspbian Stretch Lite with SSH server enabled on your microSD card. Given that, you will be able to SSH into your Raspbian Stretch Lite to perform further configurations when your Raspberry Pi is connected to your router via a network cable.
Or: Setting up Raspbian Stretch Lite with remote configuration over WiFi on first boot
So, what if you wish to connect your Raspberry Pi to your router over WiFi? In such a case, proceed to setup Raspbian Stretch Lite with remote configuration over WiFi on first boot. Given that, you will be able to SSH into your Raspbian Stretch Lite to perform further configurations when your Raspberry Pi is connected to your router via WiFi.
Assembling the hardware for your Raspberry Pi web Server
Next, remove the microSD card from your SD card reader and insert it to the microSD card slot on the Raspberry Pi 3 board. After that, proceed to assemble the Raspberry Pi 3 board to the Official Raspberry Pi case.
Starting the Raspbian Stretch Lite operating system
With the assembly of your Raspberry Pi 3 board and Official Raspberry Pi case, connect one end of the RJ45 cable to the RJ45 port on your Raspberry Pi 3 board and the other end of the cable to one of the switch port of my home router. After that, I connected my micro USB cable and supply power to my Raspberry Pi 3 board.
Changing default password, Locale and Timezone of your Raspbian Stretch Lite
There are a few configurations that we should perform on the first run of our Raspbian Stretch Lite. Therefore, proceed to change the default password, Locale and Timezone of Raspbian Stretch Lite.
Installing Nginx on Raspbian Stretch Lite
After that, install Nginx on your Raspbian Stretch Lite. To do so, enter the following command:
sudo apt-get update sudo apt-get install nginx -y
After the installation had completed, run the following command to verify that the installation is successful:
systemctl status nginx.service
The command should return the following output to tell you that Nginx was installed successfully on your Raspbian Stretch Lite:
● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2019-03-18 07:25:05 UTC; 7min ago Docs: man:nginx(8) Process: 15356 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Process: 15353 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS Main PID: 15357 (nginx) CGroup: /system.slice/nginx.service ├─15357 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; ├─15358 nginx: worker process ├─15359 nginx: worker process ├─15360 nginx: worker process └─15361 nginx: worker process Mar 19 07:25:05 raspberrypi systemd[1]: Starting A high performance web server and a reverse proxy server... Mar 19 07:25:05 raspberrypi systemd[1]: Started A high performance web server and a reverse proxy server.
Installing MariaDB database server and command line client on your Raspbian Stretch Lite
After you had installed Nginx on your Raspbian Stretch Lite, proceed to install the MariaDB database server and the command line client on your Raspbian Stretch Lite. To do so, run the following command:
sudo apt-get install mariadb-server mariadb-client -y
This installation of mariadb-server
will not prompt you for a root password. This is because the root user was by default set to use the unix_socket
plugin, which allows the user to use operating system credentials when connecting to MariaDB via Unix socket.
Since the pi
user of your Raspbian Stretch Lite installation was configured to use sudo
without password prompt, you can get into your mariadb-server
through the following command without supplying any password:
sudo mariadb
After you had ran the above command, you will be presented with an interface to interact with database server.
Installing PHP 7 on your Raspbian Stretch Lite
Next item on the list was to install the components needed to run your PHP application. For that, install PHP7, PHP7 Fast CGI Process Manager and PHP7 MySQL bridge. To install these three items, run the following command:
sudo apt-get install php7.0 php7.0-fpm php7.0-mysql -y
After the installation had completed, enter the following command to check the status:
systemctl status php7.0-fpm.service
Seeing output similar to the following will mean that your PHP Fast CGI Manager had started successfully:
● php7.0-fpm.service - The PHP 7.0 FastCGI Process Manager Loaded: loaded (/lib/systemd/system/php7.0-fpm.service; enabled; vendor prese Active: active (running) since Sat 2019-03-18 07:59:21 UTC; 1min 54s ago Docs: man:php-fpm7.0(8) Main PID: 12314 (php-fpm7.0) Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/se CGroup: /system.slice/php7.0-fpm.service ├─12314 php-fpm: master process (/etc/php/7.0/fpm/php-fpm.conf) ├─12315 php-fpm: pool www └─12316 php-fpm: pool www
Installing Certbot on Raspbian Stretch Lite for obtaining Let’s Encrypt’s browser-trusted certificates
In order to use Let's Encrypt facilities, we will need a ACME client to help us get the SSL artefacts from Let's Encrypt. Therefore, you will need to install Certbot on Raspbian Stretch Lite for obtaining Let’s Encrypt’s browser-trusted certificates.
After you had installed Certbot, you can then used it to get the SSL artefacts onto your Raspberry Pi web server.
Hosting your PHP applications on your Raspberry Pi web server
At this point in time, you are ready to host your PHP applications on your Raspberry Pi web server. In order to host your PHP applications on a LEMP stack, you may perform the following actions:
- Create a database user with privileges to interact with a database instance.
- Create database tables and execute any other SQL queries for your PHP application. When you have a PHP application that does the database initialization for you, you may skip this step. For example, in the post on setting up WordPress on Raspberry Pi 3, only a database user and a database instance was created for WordPress.
- Configure Nginx to proxy HTTP requests for dynamic content over to PHP FPM server.
- Configure Nginx to serve HTTP requests for static content.
- Use Certbot to acquire SSL artefacts for Nginx to serve HTTPS traffic with a browser trusted certificate.
- Configure Nginx to serve HTTPS traffic.
- Configure Nginx to redirect HTTP traffic to HTTPS traffic.
Using mariadb executable to administer MariaDB server
After you had installed MariaDB on your Raspberry Pi web server, you will be able to interact with the MariaDB server with mariadb
or mysql
. To get into an interactive session with MariaDB server, you can run the following command:
sudo mariadb
Creating a database instance within mariadb interactive session
Once inside the interactive session, you can then create a database instance with mariadb client:
CREATE DATABASE phpAppDb;
Creating a database user that your PHP application can use to interact with the database instance
Since it is a good practice to use a separate database user to interact with your database instance, you should proceed to do so.
Given that, run the following commands within the mariadb interactive session to create a database user and assign it full privileges to act on the database instance:
CREATE USER 'anewuser'@'localhost' IDENTIFIED BY 'password'; GRANT ALL ON phpAppDb.* TO 'anewuser'@'localhost';
After you had ran the above commands, your PHP application will then be able to use anewuser with password as the password to interact with the database instance phpAppDb.
Referencing MariaDB knowledge base for other SQL commands
In case you need to perform more database administration on your MariaDB database instance, you can refer to MariaDB's knowledge base for the list of SQL commands that you can run within the mariadb
interactive session.
Migrating your MySQL / MariaDB database from another server to your Raspberry Pi web server
When you want to setup a PHP application with data from another server, this is how you can migrate your MySQL / MariaDB database with mysqldump, tar and scp over to your Raspberry Pi web server.
Setting up phpMyAdmin to help you administer MariaDB on your Raspberry Pi web server
Since you now have a LEMP stack, you can also setup phpMyAdmin to help you administer MariaDB on your Raspberry Pi web server. After you had setup phpMyAdmin, you will get an intuitive web interface for creating the necessary database artefacts that your PHP application needs.
Nginx configurations to serve your PHP application via HTTP
Once you had prepared MariaDB for your PHP application, the next step will be to configure Nginx to serve your PHP application.
If you had gone through the guide to setup phpMyAdmin on your Raspberry Pi web server, you will get the gist of configuring Nginx to serve your PHP application.
Regardless of that, as I had mentioned in the guide to configure Nginx to serve PHP application, a typical set of Nginx configurations for serving PHP applications looks like this:
server { listen 80; server_name yourdomain.com; root /var/www/yourdomain.com; index index.php; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include fastcgi.conf; fastcgi_pass unix:/run/php/php7.0-fpm.sock; } }
In addition to that, we typically save the above content as a .conf file inside the /etc/nginx/sites-enabled
directory on your Raspberry Pi web server. Since we could have multiple .conf
files on our Raspberry Pi web server, name the files with the domain name of the website for easy identification. For example, we can name the above configuration file as yourdomain.com.conf
to label it as the configurations for serving content for yourdomain.com
.
So what does this set of Nginx configurations do?
First, the server block contains the instructions for Nginx to serve HTTP traffic for a website. With the listen directive, Nginx will listen for data at port 80. Given that the data is a valid HTTP request that has a HTTP Host header that matches what is defined with the server_name directive and/or listen directive, Nginx will handle the HTTP request according to the rules defined in this server block.
The root directive tells Nginx to look inside the /var/www/yourdomain.com
directory for resources to serve HTTP requests directed at yourdomain.com
. The index directive tells Nginx to treat any HTTP request for a directory to be treated as a request made to a index.php
file inside that directory.
When a HTTP request is made with a URL ending with .php
, Nginx will use the last location block to handle that request. Inside that location block, Nginx pass the request over to PHP FPM which will attempt to run the .php
file within the directory specified by the root
directive. Through such a configuration, your Raspberry Pi web server will be able to serve content for your dynamic website.
When a HTTP request is made with a URL that does not end with .php
, Nginx will use the first location block to handle that request. With the values specified in the try_files directive, Nginx will try to map the request to a file within the /var/www/yourdomain.com
directory. When Nginx can find a match, it returns the content of the file as a HTTP response back to the HTTP client. In the event that there is no match, Nginx will send a request to /index.php
alongside any query string variables that were included inside of the requested URL. This will in turn trigger Nginx to handle the request with the last location block.
Configuring Nginx to serve your PHP application via HTTPS
When your PHP application is not serving sensitive information, the Nginx configurations discussed so far is enough for your PHP application. In case you want to secure the communication between your Raspberry Pi web server and its client, you will need HTTPS.
In order to configure Nginx to serve your PHP application via HTTPS with a browser-trusted certificate, you need to go through the following steps:
- Configure Nginx to facilitate Certbot in acquiring the SSL artefacts for your domain or subdomain
- Run Certbot to acquire the SSL artefacts for your domain or subdomain
- Generate a strong Diffie-Hellman group
- Configure Nginx to serve your PHP application via HTTPS
Configuring Nginx to facilitate Certbot in acquiring the SSL artefacts for your domain or subdomain
First, open up your Nginx configuration with nano
:
sudo nano /etc/nginx/sites-enabled/yourdomain.com.conf
When the editor loads your configuration file, change it to look like the following:
server { listen 80; server_name yourdomain.com; root /var/www/yourdomain.com; index index.php; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include fastcgi.conf; fastcgi_pass unix:/run/php/php7.0-fpm.sock; } location ~ /.well-known { allow all; } }
After you had made the changes, type Ctrl-X followed by Y to save the file.
Once you had saved the file, restart Nginx with the following command:
sudo systemctl restart nginx.service
After you had restarted Nginx, Nginx will use the last location block to return content that are created inside /var/www/yourdomain.com/.well-known
directory. Certbot will create random files inside that directory to proof to Let's Encrypt that it is running in the web server that is reachable by the domain that it is requesting SSL artefacts for.
Running Certbot to acquire the SSL artefacts for your domain or subdomain
Next, run Certbot to acquire the SSL artefacts for your domain or subdomain:
sudo certbot certonly -a webroot --webroot-path=/var/www/yourdomain.com -d yourdomain.com
When the above command is successful, you will find the SSL artefacts from Let's Encrypt inside the /etc/letsencrypt/live/yourdomain.com
directory.
Generating a strong Diffie-Hellman group
Once Certbot had fetched the SSL certificate artefacts for your domain, generate a Diffie-Hellman group for Nginx to use for exchanging cryptographic keys with its clients:
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
Configuring Nginx to serve your PHP application via HTTPS
At this point in time, you will be ready to configure Nginx to serve your PHP application via HTTPS.
First, open up your Nginx configuration with nano
:
sudo nano /etc/nginx/sites-enabled/yourdomain.com.conf
When the editor loads your Nginx configurations for your PHP application, replace the content with the following, replacing yourdomain.com
with your domain:
server { listen 80; server_name yourdomain.com; return 301 https://$host$request_uri; } server { ssl on; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_stapling on; ssl_stapling_verify on; add_header Strict-Transport-Security max-age=15768000; listen 443; server_name yourdomain.com; root /var/www/yourdomain.com; index index.php; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include fastcgi.conf; fastcgi_pass unix:/run/php/php7.0-fpm.sock; } location ~ /.well-known { allow all; } }
After you had changed the contents, type Ctrl-X followed by Y to save the configuration file.
Once you had saved the configuration file, restart Nginx with the following command:
sudo systemctl restart nginx.service
So what does this set of Nginx configurations do?
After your Nginx instance had restarted successfully, it will listen for HTTP requests at port 80 and 443.
When Nginx picks up a HTTP request from port 80, Nginx will use the first server block to handle the request. With the configurations inside that server block, Nginx is instructed to redirect the HTTP client to send a request using the https://
uri scheme instead. This will cause the client to send a HTTP request to Nginx via the HTTPS protocol.
On the other hand, the second server block defines how Nginx should handle HTTP request directed at port 443. The set of directives from ngx_http_ssl_module configures Nginx to handle HTTPS traffic on behalf of your PHP application. Within this set of configurations, we use the ssl_certificate and ssl_certificate_key directives to point Nginx to the SSL certificate and private key that Certbot had acquired from Let's Encrypt. In addition to that we point Nginx to use ssl_dhparam directive to point Nginx to the file that we had generated openssl
with for DHE ciphers.
Apart from the ssl directives and value for the listen directive, the rest of the configurations is the same as before.
Summing it up
At this point in time, we had setup a Raspberry Pi web server that can be used serve a PHP application over HTTPS. Simply change occurrences of yourdomain.com
to a domain that you own.
In order to use this setup for your PHP application, place the source codes inside the directory specified with the root
directive. An index.php
file should also be included to hold the front controller logic that will render different views based on the requested URI.
Hosting another PHP application on the same Raspberry Pi web server
In case you wish to host another PHP application on the same Raspberry Pi web server, you will need to do the following:
- Point a new domain to the same Raspberry Pi web server
- Create a different MariaDB database instance and database user.
- Place your source codes into a different directory on the server.
- Replicate the steps defined in the Configuring Nginx to serve your PHP application via HTTPS section.
These procedures are similar to what I had covered in how to host multiple websites from home.
More examples on how to deploy PHP applications on a Raspberry Pi LEMP stack
In case you are looking for more examples on deploying PHP applications on a Raspberry Pi LEMP stack, you can refer to the following posts:
- How to host your own file sharing website on Raspberry Pi 3 with Raspbian Stretch Lite, Nginx, ProjectSend, MariaDB and PHP
- How to setup Codiad Web IDE on your Raspberry Pi 3 with Raspbian Stretch Lite, Nginx and PHP
- How to setup phpMyAdmin on a Raspbian Stretch Lite, Nginx, MariaDB / MySQL and PHP 7 LEMP stack
- Setting up WordPress on Raspberry Pi Zero W with Raspbian Stretch Lite, Nginx, MariaDB and PHP as the LEMP stack
- Setting up WordPress on Raspberry Pi 3 with Raspbian Stretch Lite, Nginx, MariaDB and PHP 7 as the LEMP stack
Buying the Raspberry Pi 3 hardware to build your own Raspberry Pi web server
If you do not have the Raspberry Pi 3 hardware mentioned in this post yet, you may want to purchase them from Amazon. Simply click on the button below to add the Raspberry Pi 3 hardware to your cart. You may remove anything that you already have or replace some of the hardware with other hardware.