mirror of
https://github.com/notrab/dumbo.git
synced 2025-01-16 21:58:25 +01:00
feat: Docker FrankenPHP and Nginx examples (#40)
This commit is contained in:
parent
db3ff52223
commit
038db48f75
35
examples/docker-frankenphp/Dockerfile
Normal file
35
examples/docker-frankenphp/Dockerfile
Normal file
@ -0,0 +1,35 @@
|
||||
# Use a specific version of the PHP image for consistency and reliability
|
||||
FROM dunglas/frankenphp:builder-php8.3-alpine
|
||||
|
||||
# Set the server name, replace "your-domain-name.example.com" with your actual domain
|
||||
# For HTTP-only setups, use ":80"
|
||||
ENV SERVER_NAME=:80
|
||||
|
||||
# Enable PHP production settings for optimized performance and security
|
||||
# RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
|
||||
|
||||
# Set the working directory for the application
|
||||
WORKDIR /app
|
||||
|
||||
# Copy the entire project directory to the container's working directory
|
||||
COPY . /app
|
||||
|
||||
# Copy Composer binary from the official Composer image for dependency management
|
||||
COPY --from=composer:2.2 /usr/bin/composer /usr/bin/composer
|
||||
|
||||
# Install Composer dependencies with optimized options for production
|
||||
RUN composer install \
|
||||
--ignore-platform-reqs \
|
||||
--no-scripts \
|
||||
--no-progress \
|
||||
--no-ansi \
|
||||
--no-dev
|
||||
|
||||
# Install required PHP extensions for the application
|
||||
RUN install-php-extensions \
|
||||
pdo \
|
||||
pdo_mysql \
|
||||
opcache
|
||||
|
||||
# Optional: Set the FRANKENPHP_CONFIG environment variable to start FrankenPHP with a specific worker script
|
||||
# ENV FRANKENPHP_CONFIG="worker ./public/index.php"
|
59
examples/docker-frankenphp/README.md
Normal file
59
examples/docker-frankenphp/README.md
Normal file
@ -0,0 +1,59 @@
|
||||
# Docker FrankenPHP Example
|
||||
|
||||
This repository provides a basic example of setting up FrankenPHP in a Docker environment using Dumbo. The provided configuration is intended as a starting point for development and production deployments.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ensure that you have [Docker](https://www.docker.com/) installed on your system.
|
||||
|
||||
## Running the Example
|
||||
|
||||
### 1. Install Dependencies
|
||||
|
||||
Before building the Docker images, you need to install the project dependencies using Composer:
|
||||
|
||||
```bash
|
||||
composer install
|
||||
```
|
||||
|
||||
### 2. Build and Start Docker Containers
|
||||
|
||||
#### Development Environment
|
||||
|
||||
To build and start the Docker containers for development:
|
||||
|
||||
1. Build the Docker images:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.yml build
|
||||
```
|
||||
|
||||
2. Start the Docker containers:
|
||||
|
||||
```bash
|
||||
docker-compose up --build app
|
||||
```
|
||||
|
||||
3. Navigate to [localhost](https://localhost).
|
||||
|
||||
#### Production Environment
|
||||
|
||||
To build and start the Docker containers for production:
|
||||
|
||||
1. Build the Docker image:
|
||||
|
||||
```bash
|
||||
docker build --tag notrab/dumbo:docker-frankenphp-example .
|
||||
```
|
||||
|
||||
2. Run the Docker container:
|
||||
|
||||
```bash
|
||||
docker run notrab/dumbo:docker-frankenphp-example
|
||||
```
|
||||
|
||||
## Further Documentation
|
||||
|
||||
For more detailed information on FrankenPHP, refer to the official documentation:
|
||||
|
||||
- [FrankenPHP Documentation](https://frankenphp.dev/)
|
12
examples/docker-frankenphp/composer.json
Normal file
12
examples/docker-frankenphp/composer.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"require": {
|
||||
"notrab/dumbo": "@dev"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../"
|
||||
}
|
||||
],
|
||||
"prefer-stable": false
|
||||
}
|
41
examples/docker-frankenphp/docker-compose.yml
Normal file
41
examples/docker-frankenphp/docker-compose.yml
Normal file
@ -0,0 +1,41 @@
|
||||
services:
|
||||
# Main application service using the FrankenPHP image
|
||||
app:
|
||||
image: dunglas/frankenphp
|
||||
networks:
|
||||
- app_network # Connect the service to the defined network
|
||||
ports:
|
||||
- "80:80" # Map port 80 on the host to port 80 in the container (HTTP)
|
||||
- "443:443" # Map port 443 on the host to port 443 in the container (HTTPS)
|
||||
- "443:443/udp" # Map UDP traffic on port 443 (useful for QUIC and HTTP/3)
|
||||
volumes:
|
||||
- ./:/app # Mount the current directory to /app in the container
|
||||
- caddy_data:/data # Persist Caddy data, such as certificates, in a named volume
|
||||
- caddy_config:/config # Persist Caddy configuration files in a named volume
|
||||
# Uncomment the following line during development to enable interactive terminal for readable logs
|
||||
# tty: true
|
||||
depends_on:
|
||||
- composer # Ensure the composer service runs before starting the app service
|
||||
|
||||
# Composer service for managing PHP dependencies
|
||||
composer:
|
||||
image: composer:2.2 # Use the official Composer image, version 2.2
|
||||
working_dir: /app # Set the working directory inside the container to /app
|
||||
volumes:
|
||||
- ./:/app # Mount the current directory to /app in the container
|
||||
entrypoint:
|
||||
- composer # Override the default entrypoint to run Composer commands
|
||||
- "--ignore-platform-reqs" # Ignore platform requirements during installation
|
||||
- "--no-progress" # Disable the progress display for a cleaner output
|
||||
- "--no-ansi" # Disable ANSI colors in the output
|
||||
command: ["install"] # Install PHP dependencies defined in composer.json
|
||||
|
||||
# Define a custom network for the services to communicate with each other
|
||||
networks:
|
||||
app_network:
|
||||
driver: bridge # Use the bridge driver for creating an isolated network
|
||||
|
||||
# Define named volumes for persisting data outside of the container lifecycle
|
||||
volumes:
|
||||
caddy_data: # Volume to store Caddy's data (like SSL certificates)
|
||||
caddy_config: # Volume to store Caddy's configuration files
|
110
examples/docker-frankenphp/public/index.php
Normal file
110
examples/docker-frankenphp/public/index.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
use Dumbo\Dumbo;
|
||||
use Dumbo\HTTPException;
|
||||
|
||||
$app = new Dumbo();
|
||||
$user = new Dumbo();
|
||||
|
||||
$userData = [
|
||||
[
|
||||
"id" => 1,
|
||||
"name" => "Jamie Barton",
|
||||
"email" => "jamie@notrab.dev",
|
||||
],
|
||||
];
|
||||
|
||||
$user->get("/", function ($c) use ($userData) {
|
||||
return $c->json($userData);
|
||||
});
|
||||
|
||||
$user->get("/:id", function ($c) use ($userData) {
|
||||
$id = (int) $c->req->param("id");
|
||||
|
||||
$user =
|
||||
array_values(array_filter($userData, fn ($u) => $u["id"] === $id))[0] ??
|
||||
null;
|
||||
|
||||
if (!$user) {
|
||||
return $c->json(["error" => "User not found"], 404);
|
||||
}
|
||||
|
||||
return $c->json($user);
|
||||
});
|
||||
|
||||
$user->post("/", function ($c) use ($userData) {
|
||||
$body = $c->req->body();
|
||||
|
||||
if (!isset($body["name"]) || !isset($body["email"])) {
|
||||
return $c->json(["error" => "Name and email are required"], 400);
|
||||
}
|
||||
|
||||
$newId = max(array_column($userData, "id")) + 1;
|
||||
|
||||
$newUserData = array_merge(["id" => $newId], $body);
|
||||
|
||||
return $c->json($newUserData, 201);
|
||||
});
|
||||
|
||||
$user->delete("/:id", function ($c) use ($userData) {
|
||||
$id = (int) $c->req->param("id");
|
||||
|
||||
$user =
|
||||
array_values(array_filter($userData, fn ($u) => $u["id"] === $id))[0] ??
|
||||
null;
|
||||
|
||||
if (!$user) {
|
||||
return $c->json(["error" => "User not found"], 404);
|
||||
}
|
||||
|
||||
return $c->json(["message" => "User deleted successfully"]);
|
||||
});
|
||||
|
||||
$app->get("/greet/:greeting", function ($c) {
|
||||
$greeting = $c->req->param("greeting");
|
||||
$name = $c->req->query("name");
|
||||
|
||||
return $c->json([
|
||||
"message" => "$greeting, $name!",
|
||||
]);
|
||||
});
|
||||
|
||||
$app->route("/users", $user);
|
||||
|
||||
$app->use(function ($ctx, $next) {
|
||||
$ctx->set("message", "Dumbo");
|
||||
return $next($ctx);
|
||||
});
|
||||
|
||||
$app->use(function ($c, $next) {
|
||||
$c->header("X-Powered-By", "Dumbo");
|
||||
|
||||
return $next($c);
|
||||
});
|
||||
|
||||
$app->get("/redirect", function ($c) {
|
||||
$message = $c->get("message");
|
||||
|
||||
return $c->redirect("/greet/hello?name=$message", 301);
|
||||
});
|
||||
|
||||
$app->get("/", function ($c) {
|
||||
$message = $c->get("message");
|
||||
|
||||
return $c->html("<h1>Hello from $message!</h1>", 200, [
|
||||
"X-Hello" => "World",
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get("/error", function ($c) {
|
||||
$customResponse = $c->html("<h1>Something went wrong</h1>", 404);
|
||||
throw new HTTPException(
|
||||
statusCode: 404,
|
||||
message: "Something went wrong",
|
||||
customResponse: $customResponse
|
||||
);
|
||||
});
|
||||
|
||||
$app->run();
|
22
examples/docker-nginx/Docker/nginx.conf
Normal file
22
examples/docker-nginx/Docker/nginx.conf
Normal file
@ -0,0 +1,22 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
root /var/www/html/public;
|
||||
index index.php index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
include fastcgi_params;
|
||||
fastcgi_pass app:9000; # This matches the PHP-FPM service in docker-compose
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
35
examples/docker-nginx/Dockerfile
Normal file
35
examples/docker-nginx/Dockerfile
Normal file
@ -0,0 +1,35 @@
|
||||
# Use the official PHP image with FPM (FastCGI Process Manager)
|
||||
FROM php:8.3-fpm
|
||||
|
||||
# Install necessary PHP extensions
|
||||
RUN docker-php-ext-install mysqli pdo pdo_mysql
|
||||
|
||||
# Install Git we'll need it for Composer
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends git
|
||||
|
||||
# Install Composer
|
||||
COPY --from=composer:2.2 /usr/bin/composer /usr/bin/composer
|
||||
|
||||
# Set the working directory in the container
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# Copy the application code to the working directory
|
||||
COPY . /var/www/html
|
||||
|
||||
# Install Composer dependencies with optimized options for production
|
||||
RUN composer install \
|
||||
--ignore-platform-reqs \
|
||||
--no-scripts \
|
||||
--no-progress \
|
||||
--no-ansi \
|
||||
--no-dev
|
||||
|
||||
# Set proper permissions for the web server
|
||||
RUN chown -R www-data:www-data /var/www/html
|
||||
|
||||
# Expose port 9000 for PHP-FPM
|
||||
EXPOSE 9000
|
||||
|
||||
# Start PHP-FPM
|
||||
CMD ["php-fpm"]
|
53
examples/docker-nginx/README.md
Normal file
53
examples/docker-nginx/README.md
Normal file
@ -0,0 +1,53 @@
|
||||
# Docker Nginx Example
|
||||
|
||||
This repository provides a basic example of setting up Nginx in a Docker environment using Dumbo. The provided configuration is intended as a starting point for development and production deployments.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ensure that you have [Docker](https://www.docker.com/) installed on your system.
|
||||
|
||||
## Running the Example
|
||||
|
||||
### 1. Install Dependencies
|
||||
|
||||
Before building the Docker images, you need to install the project dependencies using Composer:
|
||||
|
||||
```bash
|
||||
composer install
|
||||
```
|
||||
|
||||
### 2. Build and Start Docker Containers
|
||||
|
||||
#### Development Environment
|
||||
|
||||
To build and start the Docker containers for development:
|
||||
|
||||
1. Build the Docker images:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.yml build
|
||||
```
|
||||
|
||||
2. Start the Docker containers:
|
||||
|
||||
```bash
|
||||
docker-compose up --build web
|
||||
```
|
||||
|
||||
3. Navigate to [localhost](http://localhost:8080).
|
||||
|
||||
#### Production Environment
|
||||
|
||||
To build and start the Docker containers for production:
|
||||
|
||||
1. Build the Docker image:
|
||||
|
||||
```bash
|
||||
docker build --tag notrab/dumbo:docker-nginx-example .
|
||||
```
|
||||
|
||||
2. Run the Docker container:
|
||||
|
||||
```bash
|
||||
docker run notrab/dumbo:docker-nginx-example
|
||||
```
|
12
examples/docker-nginx/composer.json
Normal file
12
examples/docker-nginx/composer.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"require": {
|
||||
"notrab/dumbo": "@dev"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../"
|
||||
}
|
||||
],
|
||||
"prefer-stable": false
|
||||
}
|
42
examples/docker-nginx/docker-compose.yml
Normal file
42
examples/docker-nginx/docker-compose.yml
Normal file
@ -0,0 +1,42 @@
|
||||
services:
|
||||
# Nginx Web Server
|
||||
web:
|
||||
image: nginx:latest # Use the latest official Nginx image
|
||||
ports:
|
||||
- "8080:80" # Map port 8080 on the host to port 80 in the container
|
||||
volumes:
|
||||
- .:/var/www/html # Mount the current directory to the web root inside the container
|
||||
- ./Docker/nginx.conf:/etc/nginx/conf.d/default.conf # Use custom Nginx configuration
|
||||
depends_on:
|
||||
- app # Ensure the PHP-FPM service is started before Nginx
|
||||
networks:
|
||||
- app_network
|
||||
|
||||
# PHP-FPM Service
|
||||
app:
|
||||
build:
|
||||
context: . # Use the current directory to build the Dockerfile
|
||||
dockerfile: Dockerfile # Use the specified Dockerfile
|
||||
networks:
|
||||
- app_network
|
||||
volumes:
|
||||
- .:/var/www/html # Mount the current directory to the web root inside the container
|
||||
depends_on:
|
||||
- composer # Ensure the composer service runs before starting the app service
|
||||
|
||||
# Composer service for managing PHP dependencies
|
||||
composer:
|
||||
image: composer:2.2 # Use the official Composer image, version 2.2
|
||||
working_dir: /var/www/html # Set the working directory inside the container to /var/www/html
|
||||
volumes:
|
||||
- .:/var/www/html # Mount the current directory to /var/www/html in the container
|
||||
entrypoint:
|
||||
- composer # Override the default entrypoint to run Composer commands
|
||||
- "--ignore-platform-reqs" # Ignore platform requirements during installation
|
||||
- "--no-progress" # Disable the progress display for a cleaner output
|
||||
- "--no-ansi" # Disable ANSI colors in the output
|
||||
command: ["install"] # Install PHP dependencies defined in composer.json
|
||||
|
||||
networks:
|
||||
app_network:
|
||||
driver: bridge # Use the bridge network driver
|
110
examples/docker-nginx/public/index.php
Normal file
110
examples/docker-nginx/public/index.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
use Dumbo\Dumbo;
|
||||
use Dumbo\HTTPException;
|
||||
|
||||
$app = new Dumbo();
|
||||
$user = new Dumbo();
|
||||
|
||||
$userData = [
|
||||
[
|
||||
"id" => 1,
|
||||
"name" => "Jamie Barton",
|
||||
"email" => "jamie@notrab.dev",
|
||||
],
|
||||
];
|
||||
|
||||
$user->get("/", function ($c) use ($userData) {
|
||||
return $c->json($userData);
|
||||
});
|
||||
|
||||
$user->get("/:id", function ($c) use ($userData) {
|
||||
$id = (int) $c->req->param("id");
|
||||
|
||||
$user =
|
||||
array_values(array_filter($userData, fn ($u) => $u["id"] === $id))[0] ??
|
||||
null;
|
||||
|
||||
if (!$user) {
|
||||
return $c->json(["error" => "User not found"], 404);
|
||||
}
|
||||
|
||||
return $c->json($user);
|
||||
});
|
||||
|
||||
$user->post("/", function ($c) use ($userData) {
|
||||
$body = $c->req->body();
|
||||
|
||||
if (!isset($body["name"]) || !isset($body["email"])) {
|
||||
return $c->json(["error" => "Name and email are required"], 400);
|
||||
}
|
||||
|
||||
$newId = max(array_column($userData, "id")) + 1;
|
||||
|
||||
$newUserData = array_merge(["id" => $newId], $body);
|
||||
|
||||
return $c->json($newUserData, 201);
|
||||
});
|
||||
|
||||
$user->delete("/:id", function ($c) use ($userData) {
|
||||
$id = (int) $c->req->param("id");
|
||||
|
||||
$user =
|
||||
array_values(array_filter($userData, fn ($u) => $u["id"] === $id))[0] ??
|
||||
null;
|
||||
|
||||
if (!$user) {
|
||||
return $c->json(["error" => "User not found"], 404);
|
||||
}
|
||||
|
||||
return $c->json(["message" => "User deleted successfully"]);
|
||||
});
|
||||
|
||||
$app->get("/greet/:greeting", function ($c) {
|
||||
$greeting = $c->req->param("greeting");
|
||||
$name = $c->req->query("name");
|
||||
|
||||
return $c->json([
|
||||
"message" => "$greeting, $name!",
|
||||
]);
|
||||
});
|
||||
|
||||
$app->route("/users", $user);
|
||||
|
||||
$app->use(function ($ctx, $next) {
|
||||
$ctx->set("message", "Dumbo");
|
||||
return $next($ctx);
|
||||
});
|
||||
|
||||
$app->use(function ($c, $next) {
|
||||
$c->header("X-Powered-By", "Dumbo");
|
||||
|
||||
return $next($c);
|
||||
});
|
||||
|
||||
$app->get("/redirect", function ($c) {
|
||||
$message = $c->get("message");
|
||||
|
||||
return $c->redirect("/greet/hello?name=$message", 301);
|
||||
});
|
||||
|
||||
$app->get("/", function ($c) {
|
||||
$message = $c->get("message");
|
||||
|
||||
return $c->html("<h1>Hello from $message!</h1>", 200, [
|
||||
"X-Hello" => "World",
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get("/error", function ($c) {
|
||||
$customResponse = $c->html("<h1>Something went wrong</h1>", 404);
|
||||
throw new HTTPException(
|
||||
statusCode: 404,
|
||||
message: "Something went wrong",
|
||||
customResponse: $customResponse
|
||||
);
|
||||
});
|
||||
|
||||
$app->run();
|
Loading…
x
Reference in New Issue
Block a user