Skip to content

Instantly share code, notes, and snippets.

@rhwilr
Last active February 17, 2022 22:34
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save rhwilr/ce7338a972ef0c5585ce0c01e54bb13b to your computer and use it in GitHub Desktop.
Save rhwilr/ce7338a972ef0c5585ce0c01e54bb13b to your computer and use it in GitHub Desktop.
This is my awesome php development environment

Introduction

The following steps are required for a typical web developer stack for php and some front-end development. This is for a developer machine and not for a live environment!

Installation stack

OS installation

The OS for this DevEnv will be Antergos, an arch based, rolling release Linux distro to keep all you packages always up-to-date. Download and install Antergos. In the installation wizard please enable the following features:

  • Arch User Repository (AUR) Support
  • Extra Truetype Fonts
  • Printing Support
  • Uncomplicated Firewall
  • Windows sharing SMB

The rest of the installation is straightforward.

WebDev Environment

In the following stepts we will install the basic php and webserver components.

PHP

Let's start with php, because that's why you are here, right?

sudo pacman -S php php-fpm php-apcu php-gd php-imap php-intl php-mcrypt php-memcached php-pgsql php-sqlite php-cgi xdebug

Well, that was anticlimactic. We're already done with the php part.

Nginx

Next we install nginx as our webserver.

sudo pacman -S nginx

MySQL (MariaDB)

...and mariadb for our database.

sudo pacman -S mariadb
sudo mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql

To simplify administration, we will install mysql-workbench and phpmyadmin as a front-end.

sudo pacman -S dbeaver

Redis/Postgresql/Sqlite

Now we install three more databases. You can't have enough databases!

sudo pacman -S redis postgresql sqlite
sudo -u postgres initdb --locale $LANG -E UTF8 -D '/var/lib/postgres/data'

Memcached

As a fast, in-memory cache we use memcached. The php extension is already installed, now we install the server.

sudo pacman -S memcached

Beanstalkd

Sometimes you have tasks that can take a long while to process. Like sending emails, generating thumbnails or making external api requests. For those tasks you should use a queue, to push the process in the background and process it later when the user is not waiting. One of the tools we can use to make a queue is beanstalkd. You can also use Redis which is already installed.

yaourt -S beanstalkd

DNSMasq

And last but not least, install this one. I will tell you what it does later.

sudo pacman -S dnsmasq

Tools and Utilities

Now we can start to install a few general utilities to make our developer-life easier.

Git

Starting off with git. Git is already installed in arch, but we can set a few Settings.

git config --global color.branch auto
git config --global color.diff auto
git config --global color.status auto

git config --global user.name "John Doe"
git config --global user.email johndoe@example.com

Unless your name is actually John Doe, you should probably replace that with your name.

Composer

Composer is.. well I should not have to explain what composer is. If you don't know it, you're doing php development the wrong way.

sudo pacman -S composer

NodeJs/NPM

And the same goes for npm and front-end development.

sudo pacman -S nodejs npm

sudo npm install -g webpack gulp

PHP-CS-Fixer

To ensure that our code is psr2 compliant we can use php-cs-fixer. It will go through all your files and check them against the psr2 standard and will fix all the styling mistakes you make.

sudo wget http://get.sensiolabs.org/php-cs-fixer.phar -O /usr/local/bin/php-cs-fixer
sudo chmod a+x /usr/local/bin/php-cs-fixer

Configuration

By now we have installed everything we need. Let's start with the configuration. And like before we will start with:

PHP

sudo sed -i "s/error_reporting = .*/error_reporting = E_ALL/" /etc/php/php.ini
sudo sed -i "s/display_errors = .*/display_errors = On/" /etc/php/php.ini
sudo sed -i "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/" /etc/php/php.ini
sudo sed -i "s/memory_limit = .*/memory_limit = 512M/" /etc/php/php.ini
sudo sed -i "s/upload_max_filesize = .*/upload_max_filesize = 100M/" /etc/php/php.ini
sudo sed -i "s/post_max_size = .*/post_max_size = 100M/" /etc/php/php.ini
sudo sed -i "s/;date.timezone.*/date.timezone = UTC/" /etc/php/php.ini
sudo sed -i "s/short_open_tag = .*/short_open_tag = On/" /etc/php/php.ini

and we need to enable a few php extensions:

sudo sed -i "s/;extension=memcached.so/extension=memcached.so/" /etc/php/conf.d/memcached.ini
sudo sed -i "s/;extension=bcmath.so/extension=bcmath.so/" /etc/php/php.ini
sudo sed -i "s/;extension=bz2.so/extension=bz2.so/" /etc/php/php.ini
sudo sed -i "s/;extension=curl.so/extension=curl.so/" /etc/php/php.ini
sudo sed -i "s/;extension=exif.so/extension=exif.so/" /etc/php/php.ini
sudo sed -i "s/;extension=ftp.so/extension=ftp.so/" /etc/php/php.ini
sudo sed -i "s/;extension=gd.so/extension=gd.so/" /etc/php/php.ini
sudo sed -i "s/;extension=iconv.so/extension=iconv.so/" /etc/php/php.ini
sudo sed -i "s/;extension=imap.so/extension=imap.so/" /etc/php/php.ini
sudo sed -i "s/;extension=intl.so/extension=intl.so/" /etc/php/php.ini
sudo sed -i "s/;extension=mcrypt.so/extension=mcrypt.so/" /etc/php/php.ini
sudo sed -i "s/;extension=mysqli.so/extension=mysqli.so/" /etc/php/php.ini
sudo sed -i "s/;zend_extension=opcache.so/zend_extension=opcache.so/" /etc/php/php.ini
sudo sed -i "s/;extension=sqlite3.so/extension=sqlite3.so/" /etc/php/php.ini
sudo sed -i "s/;extension=pdo_mysql.so/extension=pdo_mysql.so/" /etc/php/php.ini
sudo sed -i "s/;extension=pdo_pgsql.so/extension=pdo_pgsql.so/" /etc/php/php.ini
sudo sed -i "s/;extension=pdo_sqlite.so/extension=pdo_sqlite.so/" /etc/php/php.ini
sudo sed -i "s/;extension=soap.so/extension=soap.so/" /etc/php/php.ini
sudo sed -i "s/;extension=sockets.so/extension=sockets.so/" /etc/php/php.ini
sudo sed -i "s/;extension=zip.so/extension=zip.so/" /etc/php/php.ini

PHP-FPM

We will set php-fpm to run under our user, so that files written by php can always be read by you and the other way around. This is something you should never ever do in production!

sudo sed -i "s/user = .*/user = $USER/" /etc/php/php-fpm.d/www.conf
sudo sed -i "s/group = .*/group = users/" /etc/php/php-fpm.d/www.conf

sudo sed -i "s/listen.owner = .*/listen.owner = $USER/" /etc/php/php-fpm.d/www.conf
sudo sed -i "s/listen.group = .*/listen.group = users/" /etc/php/php-fpm.d/www.conf

Local-SSL

We will generate a ssl certificate for our development-domain. It will be a self-signed certificate and because we are creating a wildcard certificate for a TLD (*.local), which is technically not allowed, browsers won't accept this certificate. So you will get a warning when you first visit the site. But it is always a good idea to match your dev-env as closely as you can get to your production environment. Because you're using SSL in production, right?

sudo mkdir -p /etc/ssl/webDev

sudo openssl req -nodes -newkey rsa:2048 -keyout /etc/ssl/webDev/webdev.local.key -out /etc/ssl/webDev/webdev.local.csr -subj "/CN=*.local, *.lh"
sudo openssl x509 -req -days 3650 \
                   -in /etc/ssl/webDev/webdev.local.csr  \
                   -signkey /etc/ssl/webDev/webdev.local.key  \
                   -out /etc/ssl/webDev/webdev.local.crt

Nginx

Now we configure nginx. I will use the config file attached to this Gist. Review it before you download, never blindly trust some random guy on the internet!

sudo curl -L https://gist.github.com/rhwilr/ce7338a972ef0c5585ce0c01e54bb13b/raw/nginx.conf -o /etc/nginx/nginx.conf

sudo sed -i "s/user johndoe users;/user $USER users;/" /etc/nginx/nginx.conf
sudo sed -i "s/\/home\/johndoe/\/home\/$USER/" /etc/nginx/nginx.conf

As you can see, nginx will server your websites from a webDev directory in your home. So lets create it

mkdir -p ~/webDev/log

DNSMasq

Remember when i told you I will tell you what DNSMasq does. Now it's time: So we have nginx which serves all websites ending with .local or .lh. It will grab the first part of the url and looks for a folder inside ~/webDev with that name. So to be extra cool we can use DNSMasq as a local DNS server listening for any request for a .local domain and redirect you to localhost:80. Nginx is listening on that port and will automatically serve you the correct website. So let's set this up:

sudo sed -i "s/^#conf-dir=\/etc\/dnsmasq.d\/,\*\.conf/conf-dir=\/etc\/dnsmasq.d\/,\*\.conf/" /etc/dnsmasq.conf
sudo mkdir /etc/dnsmasq.d/
echo address=/.local/127.0.0.1 | sudo tee /etc/dnsmasq.d/webDev.conf
echo address=/.lh/127.0.0.1 | sudo tee -a /etc/dnsmasq.d/webDev.conf
echo nameserver 127.0.0.1 | sudo tee /etc/resolv.conf.head

Enable services

To make all of the services we use to start up automatically, we have to enable them.

sudo resolvconf -u
sudo systemctl enable nginx.service php-fpm.service dnsmasq.service mysqld.service redis.service postgresql.service memcached.service beanstalkd
sudo systemctl start nginx.service php-fpm.service dnsmasq.service mysqld.service redis.service postgresql.service memcached.service beanstalkd

Test it out

To test that everything is working me create a index.php in ~/webDev/me/public/

mkdir -p ~/webDev/me/public
cat > ~/webDev/me/public/index.php << EOL
<?php
phpinfo();
EOL

Now open your browser end go to http://me.local/ and you should see the output of phpinfo

IDE and Git

All that's left to do is to set up your IDE. I use PhpStorm but you can use what ever you want. You will most likely find everything in the AUR.

yaourt -S phpstorm
yaourt -S smartgit

Increase inotify

To allow your IDE and Git-Clients to watch for file changes, we should increase the limit on how many watchers per user are allowed.

echo fs.inotify.max_user_watches = 524288 | sudo tee /etc/sysctl.d/99-sysctl.conf

#Xdebug To use Xdebug we first have to enable it.

sudo sed -i "s/;zend_extension=xdebug.so/zend_extension=xdebug.so/" /etc/php/conf.d/xdebug.ini
sudo sed -i "s/;xdebug.remote_enable=on/xdebug.remote_enable=on/" /etc/php/conf.d/xdebug.ini
sudo sed -i "s/;xdebug.remote_host=127.0.0.1/xdebug.remote_host=127.0.0.1/" /etc/php/conf.d/xdebug.ini
sudo sed -i "s/;xdebug.remote_port=9000/xdebug.remote_port=9000/" /etc/php/conf.d/xdebug.ini
sudo sed -i "s/;xdebug.remote_handler=dbgp/xdebug.remote_handler=dbgp/" /etc/php/conf.d/xdebug.ini

Enable Xdebug in your IDE. In PhpStorm you go to Run -> Edit Configurations... and add a new 'PHP Web Application' config.

Use the Xdebug helper Chrome-extension to use it from the Browser.

user johndoe users;
worker_processes 2;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
client_max_body_size 100m;
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
##################################
## *.local ##
##################################
server {
listen 80;
listen 443 ssl http2;
server_name *.local *.lh;
ssl_certificate /etc/ssl/webDev/webdev.local.crt;
ssl_certificate_key /etc/ssl/webDev/webdev.local.key;
set $sub 'default';
if ($host ~ "^([A-Za-z0-9\-_]+).local") {
set $project $1;
set $root /home/johndoe/webDev/$project/public;
}
if ($host ~ "^([A-Za-z0-9\-_]+).([A-Za-z0-9\-_]+).local") {
set $project $1;
set $namespace $2;
set $root /home/johndoe/webDev/$namespace/$project/public;
}
if ($host ~ "^([A-Za-z0-9\-_]+).lh") {
set $project $1;
set $root /home/johndoe/webDev/$project/public;
}
root $root;
access_log off;
error_log /home/johndoe/webDev/log/error.log;
autoindex on;
index index.php index.html;
location / {
#
# on a development server we allow content to be accessed from any where
# this allows access from different computer via ngrok or local relay server
#
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param FLOW_CONTEXT Development;
fastcgi_param FLOW_REWRITEURLS 1;
autoindex off;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_index index.php;
fastcgi_read_timeout 300;
include fastcgi.conf;
}
}
}
@calebklc
Copy link

Thank you for your gist :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment