JodGig Overview
Repository
Existing Branches
mergemerge-qa2merge-demomerge-prod
You branch out from merge to create a new feature branch.
Your branches are merged
Future
sidebar_label: 'Install PHP'
Install PHP
MacOS (Apple Silicon)
We will use homebrew to manage Mac dependencies.
As of writing this, the latest version is php@8.3.
- We will install this version.
brew install php
You will get the following output:
To enable PHP in Apache add the following to httpd.conf and restart Apache:
LoadModule php_module /opt/homebrew/opt/php/lib/httpd/modules/libphp.so
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
Finally, check DirectoryIndex includes index.php
DirectoryIndex index.php index.html
The php.ini and php-fpm.ini file can be found in:
/opt/homebrew/etc/php/8.3/
To start php now and restart at login:
brew services start php
Or, if you don't want/need a background service you can just run:
/opt/homebrew/opt/php/sbin/php-fpm --nodaemonize
Check if your system picks up php by checking the version installed.
php -v
Output:
PHP 8.3.9 (cli) (built: Jul 2 2024 14:10:14) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.9, Copyright (c) Zend Technologies
with Zend OPcache v8.3.9, Copyright (c), by Zend Technologies
You can see where php is installed with which
which php
Output:
/opt/homebrew/bin/php
Installing PHP minor version
If your codebase is not running on the latest and greatest version, for example php v8.1, you can install it via:
brew install php@8.1
Output:
==> php@8.1
To enable PHP in Apache add the following to httpd.conf and restart Apache:
LoadModule php_module /opt/homebrew/opt/php@8.1/lib/httpd/modules/libphp.so
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
Finally, check DirectoryIndex includes index.php
DirectoryIndex index.php index.html
The php.ini and php-fpm.ini file can be found in:
/opt/homebrew/etc/php/8.1/
php@8.1 is keg-only, which means it was not symlinked into /opt/homebrew,
because this is an alternate version of another formula.
If you need to have php@8.1 first in your PATH, run:
echo 'export PATH="/opt/homebrew/opt/php@8.1/bin:$PATH"' >> ~/.zshrc
echo 'export PATH="/opt/homebrew/opt/php@8.1/sbin:$PATH"' >> ~/.zshrc
For compilers to find php@8.1 you may need to set:
export LDFLAGS="-L/opt/homebrew/opt/php@8.1/lib"
export CPPFLAGS="-I/opt/homebrew/opt/php@8.1/include"
To start php@8.1 now and restart at login:
brew services start php@8.1
Or, if you don't want/need a background service you can just run:
/opt/homebrew/opt/php@8.1/sbin/php-fpm --nodaemonize
You will get an error while checking if your system picks up php.
> php -v
zsh: command not found: php
Installing specific cask with homebrew
When installing a specific version with homebrew, homebrew does not create symbolic link (symlinks) for the binaries that were installed in /opt/homebrew/Cellar/php@8.1/8.1.x.
Ensure the binary path of PHP is
So your system will not see php since it is not in the system's executable search path (e.g. /opt/homebrew/bin).
- Your shell (i.e. bash, zsh, etc) cannot find the php executable
- PHP executable is not in any of the directories listed in your PATH environment variables.
- This leads to the error above.
Install PHP's dependency manager
PHP uses composer which is a dependency manager.
MacOS: Use homebrew to install this.
- Ubuntu users can follow this guide
> brew install composer
______
/ ____/___ ____ ___ ____ ____ ________ _____
/ / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
/_/
Composer version 2.7.7 2024-06-10 22:11:12
> which composer
/opt/homebrew/bin/composer
Checking Installed PHP Extensions
Ensure that the following packages are installed by running php -m
• bcmath • ctype • fileinfo • json • mbstring • openssl • pdo • tokenizer • xml
Running php -m will list all the PHP modules.
> php -m
[PHP Modules]
bcmath
bz2
calendar
# shortened...
Install Dependencies
Navigate into the project folder root to install the project dependencies using composer
Dependencies are listed in composer.json file, similar to NodeJs package.json
composer install
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
Loading composer repositories with package information
Updating dependencies
Lock file operations: 185 installs, 0 updates, 0 removals
- Locking asm89/stack-cors (v2.2.0)
- Locking aws/aws-crt-php (v1.2.6)
# ...shortened output
Install Xdebug for debugging
For Linux and Windows, you can use xdebug's installation guide.
Assuming you installed php via homebrew, you can run this command.
pecl install xdebug
Output final lines:
Build process completed successfully
Installing '/opt/homebrew/Cellar/php@8.1/8.1.29/pecl/20210902/xdebug.so'
install ok: channel://pecl.php.net/xdebug-3.3.2
Extension xdebug enabled in php.ini
To check Xdebug was successfully installed:
php -v
Output:
PHP 8.1.29 (cli) (built: Jun 5 2024 05:51:57) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.29, Copyright (c) Zend Technologies
with Xdebug v3.3.2, Copyright (c) 2002-2024, by Derick Rethans
with Zend OPcache v8.1.29, Copyright (c), by Zend Technologies
Install PHP Debug VSCode extension
Look for PHP Debug extension in VSCode Marketplace by xdebug.
Install it.
Look for your php.ini file:
php --ini
If you installed php via homebrew, you should see:
Configuration File (php.ini) Path: /opt/homebrew/etc/php/8.1
Loaded Configuration File: /opt/homebrew/etc/php/8.1/php.ini
Scan for additional .ini files in: /opt/homebrew/etc/php/8.1/conf.d
Additional .ini files parsed: /opt/homebrew/etc/php/8.1/conf.d/ext-opcache.ini
Assuming you installed xdebug v3, open up the php.ini file, and add in
xdebug.mode = debug
xdebug.start_with_request = yes
Set up VS Code Launch Config
Create a Launch Configuration in VSCode for PHP
Replace the generated Listen for Xdebug with the following configurations:
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"runtimeExecutable": "php",
"runtimeArgs": [
"-dxdebug.mode=debug", // tells Xdebug to start in debug mode. -d flag used to set php.ini settings
"-dxdebug.start_with_request=yes", // tells Xdebug to start debugging immediately when a request is received
"artisan", // Laravel command line to interact with the PHP app
"serve", // Artisan command to start the Laravel development server
"--host=localhost", // Host to bind the server to
"--port=8001" // Port to bind the server to
],
"cwd": "${workspaceRoot}", // Tell debugger to run `php` in the Current Working Directory (cwd)
"env": {
"XDEBUG_MODE": "debug", // Ensure xdebug can read it during runtime, and not only startup
"XDEBUG_CONFIG": "client_port=${port}"
}
},
sidebar_label: 'Project Setup'
JodGig Project Setup
Esnure you have PHP v8.3 installed in your local machine.
Install passport
If you tried running the server immediately after installing PHP, you might have encountered the following error:
[2024-10-17 18:54:28] local.ERROR: Invalid key supplied {"exception":"[object] (LogicException(code: 0): Invalid key supplied at /Users/alaay/projects/jodgig/jodgig-api/vendor/league/oauth2-server/src/CryptKey.php:67)
[stacktrace]
#0 /Users/username/projects/jodgig/jodgig-api/vendor/laravel/passport/src/PassportServiceProvider.php(275): League\\OAuth2\\Server\\CryptKey->__construct('file:///Users/a...', NULL, false)
#1 /Users/username/projects/jodgig/jodgig-api/vendor/laravel/passport/src/PassportServiceProvider.php(256): Laravel\\Passport\\PassportServiceProvider->makeCryptKey('public')
This is because we have not installed passport locally.
The project uses passport for OAuth2 authentication (for some reason).
php artisan passport:install
Output:
Encryption keys generated successfully.
Personal access client created successfully.
Client ID: 5
Client secret: <client secret key>
Password grant client created successfully.
Client ID: 6
Client secret: <client secret key>
passport:install will do two things:
-
Creates two files
./storage/oauth-private.key./storage/oauth-public.key
-
Inserts into the database table
oauth_clients- Depending on what sql dump you got to load your DB, you're Client ID in your output will be different.
Overview
Start the local server
This will start the server on your machine running at localhost:8001
compose start
This will run the start script defined in composer.json
"start": "php artisan serve --host=localhost --port=8001"
sidebar_label: 'Dockerising JodGig'
Dockerising JodGig for Deployment Notes
These are notes based on recent deployment of JodGig onto AWS EC2 by Ali.
Laravel depends on the following key components:
- PHP-FPM (FastCGI Process Manager)
- Nginx (web server)
PHP-FPMis the core component that handles PHP code execution and interacts with the web server.
- It's responsible for managing PHP processes, optimizing performance, and handling requests efficiently.
Nginx acts as a reverse proxy server, routing incoming requests to the appropriate PHP-FPM process.
Docker Strategy
Use docker compose to setup the services
- Nginx
- PHP-FPM
Nginx will receive the HTTP requests and forward them to PHP-FPM.
- PHP-FPM cannot accept HTTP requests directly since it only supports FastCGI protocol.
Configuration Files
Inside docker container with php-8.1
/usr/local/etc/
pear.conf
php-fpm.conf
php-fpm.conf.default
php-fpm.d/
docker.conf
www.conf
www.conf.default
zz-docker.conf
php/
php.ini-development
php.ini-production
conf.d/
docker-fpm.ini
docker-php-ext-bcmath.ini
docker-php-ext-exif.ini
docker-php-ext-gd.ini
docker-php-ext-intl.ini
docker-php-ext-pcntl.ini
docker-php-ext-pdo_mysql.ini
docker-php-ext-redis.ini
docker-php-ext-sodium.ini
docker-php-ext-zip.ini
Two config files we need to take note of when building the Docker image with Dockerfile:
www.confphp.ini-production
www.conf
An important configuration file for php-fpm (FastCGI Process Manager) that controls how PHP processes are managed when running PHP apps like Laravel.
Configures:
- php-fpm pool settings
- controls how PHP processes are managed
- e.g. number of child processes, process manager settings, etc.
- php-fpm logging and error handling
- defines resource limits (e.g. memory, CPU) for PHP processes
www.config configs examples
| config | description |
|---|---|
pm.max_children | Maximum number of child processes that can be spawned by php-fpm. |
pm.start_servers | Minimum number of child processes that will be started by php-fpm when the pool is first initialized. |
pm.min_spare_servers | Minimum number of idle child processes that should be kept running by php-fpm. |
pm.max_spare_servers | Maximum number of idle child processes that should be kept running by php-fpm. |
pm.process_idle_timeout | Maximum number of seconds a child process can remain idle before it is terminated. |
php.ini-production
sidebar_label: 'Deployment Overview'
JodGig Deployment Overview
JodGig consists of two services:
- Frontend
- API
Both are deployed directly into two different EC2 instances.
jodgig.<env>.frontendjodgig.<env>.api
Where <env> is the environment:
qademoproduction
Overview
- User makes HTTP requests which get routed to
haproxyvia Cloudflare DNS. - HTTP requests with the url
jodapp.comwill be forwarded to the frontend service. - HTTP requests with the url
jodaopp.com/apiwill be forwarded to the api service.
API
Inside API EC2 instance, we have 2 docker containers running:
php-fpm_YYYYMMDD_HHMMSSnginx
Nginx
We require nginx to receive HTTP requests from Haproxy. php-fpm by itself cannot receive HTTP requests. It is a FastCGI process.
nginx will receive the HTTP request, and then forward a FastCGI request over TCP/IP to php-fpm through the docker network api_default.
Traditionally PHP-FPM might use Unix sockets for communication when on the same machine. In our case, we are using TCP/IP to communicate between nginx and php-fpm via the docker network api_default.
PHP-FPM
PHP-FPM is a FastCGI process. It is used to process PHP files. nginx will forward PHP requests to php-fpm.
It will handle the PHP requests that come from nginx.
Frontend
Inside Frontend EC2 instance, we do not have any docker containers running. Instead we have pm2, a node process manager running. It only handles a single node process called serve.
serveis a lightweight server for serving static files.
sidebar_label: 'Deployment Process'
JodGig Deployment Process
The new deployment process is designed in a way to fix previous issues faced when deploying to production:
- Deployment takes ~8-15minutes
- Build constantly fails due to LetsEncrypt quota reaching limit
- Deployment has to happen during off-peak hours
Overview
We use simple bash scripts to automate deployment for both API and Frontend.
JodGig API
~/deploy/deploy.sh is the file that we use to deploy the API.
- Determine if oauth keys exist. If not, exit the script.
- Create the docker network if it doesn't exist
- This is for
nginxcontainer to forward requests tophp-fpmcontainer
- This is for
- Build the
php-fpmdocker image. - Run the new
php-fpmcontainer using the newly built image alongside the oldphp-fpmcontainer - In a loop, check the health the new
php-fpmcontainer until it's ready. - Once ready, run database migrations in the new
php-fpmcontainer.
At this point, we need to point nginx to the new php-fpm container.
- Update
~/api/deploy/nginx/conf.d/default.confto point to the newphp-fpmcontainer. - Restart the
nginxcontainer to pick up the new configuration. - Stop the old
php-fpmcontainer