EOS LEMP Web development platform
To make things easier for myself as a PHP web developer I set up localhost to be my web server and develop locally before uploading files to the necessary server. This works very effectively using the LEMP stack ( Linux NGINX MariaDB PHP ), which in my experience is faster than LAMP / Apache.
Disclaimer:
You need to be at least slightly familiar with PHP, and the command line in order to work this. In the examples below I will use “mydomain.local” as the example domain to develop for; change it to yours. Likewise with “username”.
This is not the most secure way of setting up a webserver; it’s not supposed to be, it’s supposed to be the easiest to work with in offline development.
I welcome any critique and corrections to this guide, but I have found this has worked for me running under Antergos/EOS for the last 2+ years and similar configuration on Mint/Debian for the last 10 years.
Concept one:
Your /etc/hosts file controls how your machine sees the internet and domain names. You are going to develop for a specific domain name, so the best way to control this is by modifying the /etc/hosts file.
Add a line to it to control access to the domain name mydomain.local like this:
sudo nano /etc/hosts
add:
127.0.0.1 mydomain.local
ctrl-x, y, enter
Concept two:
In almost every other tutorial for local development they will suggest that you are keeping the website files in /var/www or similar. This has some drawbacks that are significant, in that it is outside your easily backed-up /home folders. Unfortunately I have not managed to get MariaDB to be happy about moving it’s DB files, so you need to have a database backup plan.
Concept three:
Updates to systemd have historically borked my methods here, so lookout for that as an answer if things stop working for you. I list one such fix below.
NB: // below denotes a comment
Recipe
// updates system first
sudo pacman -Syu
// install nginx
sudo pacman -S nginx-mainline
// enable the nginx service
sudo systemctl enable nginx
// stop the service if it is already running, because we’re going to change things…
sudo systemctl stop nginx
// install mariaDB
sudo pacman -S mariadb
// initialize the database
sudo mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql
// enable and start mariadb
sudo systemctl enable mariadb && systemctl start mariadb
// set a root user password for mariadb, answer Y to all
mysql_secure_installation
// login to mariadb with the root password just set, type quit to exit
mysql -u root -p
// install php
sudo pacman -S php php-fpm
// enable php
sudo systemctl enable php-fpm
// now we will set our custom directories for working files, working within our home folder gives us all rights
mkdir ~/htdocs
mkdir ~/htdocs/sites
mkdir ~/htdocs/database
mkdir ~/htdocs/backups
mkdir ~/htdocs/errorpages
mkdir ~/htdocs/logs
mkdir ~/htdocs/sites-enabled
mkdir ~/htdocs/tmp
// phpmyadmin: it is possible to use the package manager to install phpmyadmin. However I prefer to install it separately like so:
cd ~/htdocs/database
wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz
tar -zxvf phpMy*
ls -la php*
// see what the directory retrieved from the tar.gz is called, then move it to be pma/, so the line below is only example!
mv phpMyAdmin-5.0.2-all-languages/ pma/
cd ~/htdocs/sites-enabled
nano pma.local
// Enter the following between the hashed lines, taking care to change the username to yours
##################################################################################
server {
root /home/username/htdocs/database/pma;
index index.php;
access_log /home/username/htdocs/logs/pma.local.access.log;
error_log /home/username/htdocs/logs/pma.local.error.log;
server_name pma.local;
client_max_body_size 256M;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
location ~ \.php$ {
try_files $uri $document_root$fastcgi_script_name =404;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_read_timeout 180000;
include fastcgi.conf;
# prevention for httpoxy vulnerability: https://httpoxy.org/
fastcgi_param HTTP_PROXY "";
}
location ~ /\.ht {
deny all;
}
}
##################################################################################
ctrl-x, y, enter
// add pma.local to the hosts as per Concept One above
sudo nano /etc/hosts
// add:
127.0.0.1 pma.local
ctrl-x, y, enter
// now we can modify nginx config files to serve from our directories
sudo nano etc/nginx/nginx.conf
// Enter the following between the hashed lines, taking care to change the username to yours
##################################################################################
user username; # <--- this sets nginx up to run as you!
worker_processes 8;
error_log /home/username/htdocs/logs/nginx-error.log info;
events {
worker_connections 1024;
}
http {
types_hash_max_size 1024;
include mime.types;
default_type application/octet-stream;
access_log /home/username/htdocs/logs/nginx-access.log;
sendfile on;
keepalive_timeout 65;
gzip on;
server { # <-- the default localhost server accessed through http://localhost
listen 80; # <-- what TCP/IP port nginx will listen on
server_name localhost; <-- aka 127.0.0.1
location / {
root /home/username/htdocs/sites/; # <-- default root. Each development site should own another directory under this
index index.php index.html index.htm; # <-- the filenames that nginx looks for as the default for a directory
}
# redirect server error pages to the static page /50x.html
#
error_page 404 500 502 503 504 /50x.html;
location = /50x.html {
root /home/username/htdocs/errorpages/;
}
location ~ \.php$ {
root /home/username/htdocs/sites/;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server <-- example syntax only; there's not much point in using SSL connections locally
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
include sites-enabled/*;
include /home/username/htdocs/sites-enabled/*; # <-- we can easily create new site definitions in that folder and nginx will pick them up
##################################################################################
ctrl-x, y, enter
// make new site definition for nginx for our example domain
nano /home/username/htdocs/sites-enabled/mydomain.local
##################################################################################
server {
server_name mydomain.local;
root /home/username/htdocs/sites/mydomain; # <-- where your site files live
client_max_body_size 512M;
access_log off;
error_log /home/username/htdocs/logs/mydomain.local-error.log error; # <-- where your error logs go
index index.php;
location = /favicon.ico {
log_not_found off;
access_log off;
}
# Very rarely should these ever be accessed outside of your lan
location ~* \.(txt|log)$ {
allow 127.0.0.1;
deny all;
}
location ~ \..*/.*\.php$ {
return 403;
}
location ~ \.php$ {
try_files $uri $document_root$fastcgi_script_name =404;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi.conf;
# prevention for httpoxy vulnerability: https://httpoxy.org/
fastcgi_param HTTP_PROXY "";
send_timeout 86400; # <-- all of these settings are set high because there is no balancing required on a local environment
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
proxy_connect_timeout 600m;
proxy_send_timeout 600m;
proxy_read_timeout 600m;
fastcgi_send_timeout 600m;
fastcgi_read_timeout 600m;
}
}
##################################################################################
ctrl-x, y, enter
// now we work on PHP configuration
sudo nano /etc/php/php-fpm.d/www.conf
// Enter the following between the hashed lines, taking care to change the username to yours
##################################################################################
error_log = /home/username/htdocs/logs/php-fpm.log
[www]
user = username
group = username
listen = /run/php-fpm/php-fpm.sock
listen.owner = username
listen.group = username
pm = dynamic
pm.max_children = 8
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
rlimit_core = unlimited
##################################################################################
ctrl-x, y, enter
// the php.ini file controls most of the environment for php’s engine, but requires tuning for your needs. Of particular importance are the Dynamic Extensions
// mine pays attention to the following switches:
sudo nano /etc/php/php.ini
##################################################################################
;extension=bcmath
;extension=bz2
;extension=calendar
extension=curl
;extension=dba
;extension=enchant
;extension=exif
extension=ftp
;extension=gd
;extension=gettext
;extension=gmp
;extension=iconv
;extension=imap
;extension=intl
;extension=sodium
;extension=ldap
extension=mysqli
;extension=odbc
;zend_extension=opcache
;extension=pdo_dblib
extension=pdo_mysql
;extension=pdo_odbc
;extension=pdo_pgsql
;extension=pdo_sqlite
;extension=pgsql
;extension=pspell
;extension=shmop
;extension=snmp
;extension=soap
;extension=sockets
extension=sqlite3
;extension=sysvmsg
;extension=sysvsem
;extension=sysvshm
;extension=tidy
extension=xmlrpc
;extension=xsl
extension=zip
upload_max_filesize = 256M
memory_limit = 512M
max_input_time = -1
date.timezone = Pacific/Auckland
open_basedir = /srv/http/:/var/www/:/home/username/htdocs/:/tmp/:/var/tmp/:/var/cache/:/usr/share/pear/:/usr/share/webapps/:/etc/webapps/
##################################################################################
ctrl-x, y, enter
// put a test page in for php
nano /home/username/htdocs/sites/index.php
##################################################################################
<?php
phpinfo();
?>
##################################################################################
ctrl-x, y, enter
// start the engines
sudo systemctl start nginx
sudo systemctl start php-fpm
// If all is well, no errors displayed, then you can open a web browser and go to http://localhost to see the PHP info screen
// then start filling up /home/username/htdocs/sites/mydomain with your new PHP files, etc. usually starting with an index.php
// Also you can use PHPMyAdmin at http://pma.local
// If there are errors starting up then use:
journalctl -xe
// to determine what the problem is. There may be issues with permissions so you have to force ownership of a socket file, eg:
sudo chown username:username /run/php-fpm/php-fpm.sock
==============================================================================
//EOF
==============================================================================
FOSS IDE / Programming Tools:
These are very much a personal taste thing, so find what works for you.
Filezilla is an excellent way to connect to remote server via SFTP and push/pull files.
Geany is a lightweight GTK IDE for many languages, but handles PHP/HTML/CSS/Javascript with ease, and can be paired with Filezilla for remote file editing.
Komodo Edit or Komodo IDE are great lightweight editors for our purposes. The IDE version needs to be downloaded from their website with version 12, and this can work with Xdebug PHP debugger.
NetBeans 12 is big, slow, and powerful. But in my experience a bit temperamental with it’s debugger handling.
VS Code is Microsoft’s attempt to influence developers on Linux. Not for me; ymmv.
Atom is a lightweight text editor that annoys me with it’s layout. Ymmv.
Xdebug is the PHP debugger.
… there are many more, including Kate for KDE …
Links:
Nginx: https://wiki.archlinux.org/index.php/Nginx
MariaDB: https://wiki.archlinux.org/index.php/MariaDB
PHP: https://wiki.archlinux.org/index.php/PHP
PHPMyAdmin: https://wiki.archlinux.org/index.php/phpMyAdmin
https://bbs.archlinux.org/viewtopic.php?pid=1875352#p1875352 <-- Fix a problem where after PHP update files are no longer working from /home folders due to ProtectHome switch in systemd