In real-world software projects, jumping into something new can be challenging, especially when it involves unfamiliar domains, frameworks, languages, or coding styles. So, how do you effectively approach these new challenges?
Docker is a powerful tool for building, managing, and hosting services locally, which comes in handy when working on project with the Cognitive framework in PHP. In the Cognitive framework for PHP, when you generate project, you will find `doc_root` directory where you configure `.htaccess`. This setup can be used with docker pull httpd to run the application inside Docker container.
flagtickgroup\
├── docker
├── app.flagtick\
├── cdn.flagtick\
├── listener.flagtick\
└── docker\
└── mysql\
└── databases\
For each of the directories such as `app.flagtick`, `cdn.flagtick`, and `listener.flagtick`. You will need to initialize Composer and install CodeIgniter 4. Follow these steps for each directory:
app.flagtick/
├── application/
├── doc_root/
│ └── .htaccess
├── vendor/
├── .gitignore
├── .gitlab-ci.yml
├── composer.json
├── composer.lock
└── system/
Now conduct to create Docker setup for your project using the httpd (Apache HTTP Server) image and configure it with a `.htaccess` file, you will need to create `docker-compose.yml` file and possibly Dockerfile if additional customization is needed.
» `docker-compose.yml`
fg_http:
container_name: fg-http
build: ./docker/php
image: fg_httpd
restart: always
volumes:
- ./app.flagtick:/var/www/app.flagtick:cached
- ./cdn.flagtick:/var/www/cdn.flagtick:cached
- ./listener.flagtick:/var/www/listener.flagtick:cached
- ./docker/mysql/databases:/home/database:cached
depends_on:
- db1
command:
- /bin/sh
- -c
- |
init.sh
echo "-----------------------------------"
echo "containers ready!!!!!"
echo "--------------------------"
echo "Can now fire up"
echo "- https://local.flagtick.com"
echo "- https://local-listener.app.com"
echo "- https://local-cdn.flagtick.com"
echo "-----------------------------------"
echo "-----------------------------------"
apache2-foreground
networks:
web_server:
aliases:
- local.flagtick.com
- local-cdn.flagtick.com
We can define two folders, such as resources and tools, to export files from a local machine to Linux environment in Docker by using volumes.
flagtickgroup\
├── app.flagtick\
├── cdn.flagtick\
├── listener.flagtick\
├── docker\
│ └── mysql\
│ └── databases\
├── resources\
└── tools\
» `docker-compose.yml`
volumes:
- ./app.flagtick:/var/www/app.flagtick:cached
- ./cdn.flagtick:/var/www/cdn.flagtick:cached
- ./listener.flagtick:/var/www/listener.flagtick:cached
- ./docker/mysql/databases:/home/database:cached
- ./tools/bpmn:/usr/local/bin/bpmn:cached
- ./resources/media:/home/httpd/sites/media:cached
When you are working with Docker and need to tailor your setup, especially for PHP application with Apache, there are several key customization steps you might consider. Here is a breakdown of what you can do to make your Dockerfile fit your specific needs:
Customize your Dockerfile, first create `docker` folder with subfolder named `php`. Place all the necessary files for your local setup in the `php` folder before replicating them to your Docker host environment.
build: ./docker/php
The `php` folder looks like this:
|_ flagtick.com.conf
|_ Dockerfile
|_ hosts
|_ init.sh
|_ php.ini
|_ server.conf
|_ xdebug.ini
└───wild
|_ flagtick.com.crt
|_ flagtick.com.csr
|_ flagtick.com.key
|_ gd_bundle-g2-g1.crt
If you need to run different PHP version for specific endpoints, you can create custom folder named `phpx` in your Docker directory. Then, use the build attribute to point to this `phpx` folder and set it up.
» `docker-compose.yml`
fl_http:
container_name: fl-http
build: ./docker/phpx
volumes:
- ./api.flagtick:/var/www/api.flagtick
command:
- /bin/sh
- -c
- |
init.sh
echo "----------------------------------"
echo "containers ready!!!!!"
echo "----------------------------------"
echo "Can now fire up"
echo "- https://local-api.flagtick.com"
echo "----------------------------------"
apache2-foreground
networks:
web_server:
aliases:
- local-api.flagtick.com
As you can see, we have set `depends_on` to only rely on db1. This means we need to make sure the database service (db1) is up and running before moving on to the httpd service.
» `docker-compose.yml`
db1:
container_name: fg-mysql
build: ./docker/mysql
image: fg_mysql
restart: always
volumes:
- ./resources/db:/usr/local/resources/db
environment:
MYSQL_ROOT_PASSWORD: "root"
ports:
- "3306:3306"
networks:
- web_server
or another service using a different MySQL version.
db8:
container_name: fg-mysqlx
build: ./docker/mysqlx
restart: always
volumes:
- db_datax:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: "root"
command:
--default-authentication-plugin=mysql_native_password
ports:
- "9906:3306"
networks:
- web_server
By mapping port 3306 in the container to the host, MySQL will be accessible on the host's port 3306. You can use `curl`, `telnet`, or `nc` to check if the service is running.
curl localhost:3306
Besides, you can test connectivity by using MySQL clients or other terminal tools:
mysql -h 127.0.0.1 -P 3306 -u root -p
You can check if the service is live using curl. Once your container is running, use curl to make a request to the service to verify it is up and accessible.
curl -I https://local.flagtick.com
In Docker Desktop, go to the Containers tab, click the menu overflow, select Exec, and run the commands shown in the screenshot below.
This is what batch mode looks like:
# curl -I https://local.flagtick.com
HTTP/1.1 200 OK
Date: Mon, 09 Sep 2024 14:13:34 GMT
Server: Apache/2.4.52 (Debian)
X-Powered-By: PHP/7.3.33
Set-Cookie: ci_session=i8c8poed5b5tsh2bikgje13p3t355iee; expires=Mon, 09-Sep-2024 16:13:35 GMT; Max-Age=7200; path=/; domain=local.flagtick.com; secure; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Set-Cookie: ci_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=local.flagtick.com; secure; HttpOnly
Set-Cookie: ci_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=.local.flagtick.com; HttpOnly
Set-Cookie: ci_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=.flagtick.com; HttpOnly
Set-Cookie: ci_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=.flagtick; HttpOnly
Set-Cookie: sys_language=en; expires=Sun, 25-Jan-2088 17:46:55 GMT; Max-Age=2000000000; path=/; domain=local.flagtick.com; secure
Set-Cookie: sys_c_timestamp=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=local.flagtick.com; secure
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=UTF-8
Running `curl -I https://local.flagtick.com` on your local machine will produce results like this:
curl -I https://local.flagtick.com
curl: (7) Failed to connect to local.flagtick.com port 443 after 2071 ms: Couldn't connect to server
The problem is with copying Apache configuration files. To get `local.flagtick.com` running locally with Apache, just set up `servername.conf`, configure it, and then move it to Docker on your desktop.
» `servername.conf`
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName local.flagtick.com
DocumentRoot /var/www/local.flagtick
SSLEngine on
SSLCertificateFile /etc/ssl/certs/flagtick.com.crt
SSLCertificateKeyFile /etc/ssl/private/flagtick.com.key
<Directory /var/www/local.flagtick>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/local.flagtick_error.log
CustomLog ${APACHE_LOG_DIR}/local.flagtick_access.log combined
</VirtualHost>
</IfModule>
<VirtualHost *:80>
ServerName local.flagtick.com
Redirect permanent / https://local.flagtick.com/
</VirtualHost>
Use the `Dockerfile` in the docker/php or docker/phpx folder to move your local setup to the Docker environment. Just make sure your source code is properly defined.
» `Dockerfile`
...
COPY ./servername.conf /etc/apache2/conf-available/
...
RUN a2enconf servername.conf
If you would prefer to go with the Nginx -> Apache -> Service setup instead of Apache -> Service, you might want to simplify things a bit. One easy step is to remove the configurations for servername.conf. This can help streamline your setup and make it easier to manage.
By focusing on using Nginx as the front-end proxy, you let it handle the HTTPS connections, and Apache can then focus on serving your application.
» `servername.conf`
ServerName flagtick.com
Once port 3306 is open, you can set up the `phpmyadmin/phpmyadmin` Docker container to provide visual UI for managing and interacting with your MySQL database easily.
» `docker-compose.yml`
phpmyadmin:
container_name: fg-phpmyadmin
image: phpmyadmin/phpmyadmin
environment:
- PMA_ARBITRARY=1
restart: always
volumes:
- "./docker/phpmyadmin/config.user.inc.php:/etc/phpmyadmin/config.user.inc.php"
networks:
- web_server
Since you are not exposing any ports directly in the phpmyadmin service, you can use reverse proxy setup with Nginx (or another web server) to access phpMyAdmin by aliasing domain and forwarding the requests to the correct container.
Next, we will cover the final section of the `docker-compose.yml` file, which involves setting up the Nginx server.
nginx:
container_name: "fg-nginx"
build: ./docker/nginx
ports:
- "80:80"
- "443:443"
depends_on:
- fl_php
volumes:
- "./docker/nginx/timeout.conf:/etc/nginx/conf.d/timeout.conf"
- "./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf"
networks:
- web_server
You can access `localhost:80` or `localhost:443` from your local machine if the Docker container is running and the ports are correctly mapped.
In Apache HTTP server, multiple aliases for multiple virtual hosts means configuring various domain names or subdomains to direct traffic to different virtual hosts, each serving distinct website or application.
» `/etc/httpd/conf.d/` or `/etc/apache2/sites-available/`
Here is typical Nginx configuration that demonstrates how to set up reverse proxying and SSL for various upstream servers and domains.
» `default.conf`
# Define upstream servers
upstream backend1 {
server fg_http:443;
}
upstream backend2 {
server fl_http:443;
}
upstream pma {
server phpmyadmin:80;
}
# HTTP Server Block for phpMyAdmin and similar services
server {
listen 80;
server_name local-pma.flagtick.com pma.flagtick.local;
location / {
proxy_set_header Host $host;
proxy_pass http://pma;
}
}
# HTTPS Server Block for RPM and related services
server {
listen 443 ssl;
client_max_body_size 64M;
large_client_header_buffers 8 64k;
server_name local-api.flagtick.com;
location / {
proxy_set_header Host $host;
proxy_pass https://backend2/;
}
ssl_certificate /etc/ssl/flagtick.com.crt;
ssl_certificate_key /etc/ssl/flagtick.com.key;
}
# HTTPS Server Block for wildcard domains
server {
listen 443 ssl;
client_max_body_size 64M;
large_client_header_buffers 8 64k;
server_name *.flagtick.com;
location / {
proxy_set_header Host $host;
proxy_pass https://backend1/;
}
ssl_certificate /etc/ssl/flagtick.com.crt;
ssl_certificate_key /etc/ssl/flagtick.com.key;
}
After you have successfully reconfigured the Nginx server, run the command `curl -I https://local.flagtick.com` again to check if everything is working.
# curl -I https://local.flagtick.com/
HTTP/1.1 200 OK
Server: nginx/1.18.0
Date: Tue, 10 Sep 2024 15:21:38 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/7.3.33
Set-Cookie: ci_session=9v1bi8lg9bjqn6au1ruia26j2ceqa7as; expires=Tue, 10-Sep-2024 17:21:38 GMT; Max-Age=7200; path=/; domain=local.flagtick.com; secure; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Set-Cookie: ci_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=local.flagtick.com; secure; HttpOnly
Set-Cookie: ci_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=.local.flagtick.com; HttpOnly
Set-Cookie: ci_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=.flagtick.com; HttpOnly
Set-Cookie: ci_session=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=.clinic; HttpOnly
Set-Cookie: sys_language=en; expires=Mon, 26-Jan-2088 18:54:58 GMT; Max-Age=2000000000; path=/; domain=local.flagtick.com; secure
Set-Cookie: sys_c_timestamp=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=local.flagtick.com; secure
Access-Control-Allow-Origin: *
II.
Go with phpmyadmin and nginx