Skip to content

Commit 9d76376

Browse files
committed
feature(app): Implement FrankenPHP classic stack.
1 parent 478e4c8 commit 9d76376

File tree

17 files changed

+445
-50
lines changed

17 files changed

+445
-50
lines changed

.github/workflows/build.yml

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,32 @@ on:
1818
name: build
1919

2020
jobs:
21-
codeception:
22-
uses: php-forge/actions/.github/workflows/codeception.yml@main
23-
secrets:
24-
AUTH_TOKEN: ${{ secrets.AUTH_TOKEN }}
25-
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
26-
with:
27-
codeception-command: vendor/bin/codecept run --env php-builtin --coverage-xml
28-
coverage-file: runtime/output/coverage.xml
29-
extensions: gd, intl, pcov
21+
nginx:
22+
runs-on: ubuntu-latest
23+
24+
steps:
25+
- name: Checkout.
26+
uses: actions/checkout@v5
27+
28+
- name: Docker version.
29+
run: |
30+
docker version
31+
docker compose version
32+
33+
- name: Build and start containers.
34+
run: docker compose up -d --build
35+
36+
- name: Wait for readiness.
37+
run: |
38+
for i in {1..60}; do
39+
if docker exec yii2-frankenphp sh -lc "curl -ksS -o /dev/null -w '%{http_code}' https://localhost | grep -qE '200|302'"; then
40+
echo "Service is ready"; exit 0; fi
41+
sleep 2
42+
done
43+
echo "Service not ready"; docker logs yii2-frankenphp; exit 1
44+
45+
- name: Codeception build.
46+
run: docker exec yii2-frankenphp vendor/bin/codecept build
47+
48+
- name: Codeception tests.
49+
run: docker exec yii2-frankenphp vendor/bin/codecept run

README.md

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
<a href="https://github.com/yiisoft/yii2/tree/22.0" target="_blank">
1616
<img src="https://img.shields.io/badge/22.0.x-0073AA.svg?style=for-the-badge&logo=yii&logoColor=white" alt="Yii 22.0.x">
1717
</a>
18-
<a href="https://github.com/yii2-extensions/app-basic/actions/workflows/build.yml" target="_blank">
19-
<img src="https://img.shields.io/github/actions/workflow/status/yii2-extensions/app-basic/build.yml?branch=main&style=for-the-badge&label=Codeception" alt="Codeception">
18+
<a href="https://github.com/yii2-extensions/app-basic/actions/workflows/build.yml?query=branch%3Afranken-php-classic" target="_blank">
19+
<img src="https://img.shields.io/github/actions/workflow/status/yii2-extensions/app-basic/build.yml?branch=franken-php-classic&style=for-the-badge&label=Codeception" alt="Codeception">
2020
</a>
21-
<a href="https://github.com/yii2-extensions/app-basic/actions/workflows/static.yml" target="_blank">
22-
<img src="https://img.shields.io/github/actions/workflow/status/yii2-extensions/app-basic/static.yml?branch=main&style=for-the-badge&label=PHPStan" alt="PHPStan">
21+
<a href="https://github.com/yii2-extensions/app-basic/actions/workflows/static.yml?query=branch%3Afranken-php-classic" target="_blank">
22+
<img src="https://img.shields.io/github/actions/workflow/status/yii2-extensions/app-basic/static.yml?branch=franken-php-classic&style=for-the-badge&label=PHPStan" alt="PHPStan">
2323
</a>
2424
</p>
2525

@@ -40,24 +40,6 @@ A modern, Bootstrap 5-powered Yii2 application template designed for rapid web-a
4040
-**Modern Bootstrap 5 UI** - Responsive, mobile-first design with latest Bootstrap components.
4141
-**Testing Ready** - Codeception test suite with examples for functional and unit testing.
4242

43-
## Available deployment options
44-
45-
### Traditional Web Servers
46-
47-
Classic web-server + PHP-FPM setup; simple and widely supported for deployment.
48-
49-
[![Apache](https://img.shields.io/badge/apache-%23D42029.svg?style=for-the-badge&logo=apache&logoColor=white)](https://github.com/yii2-extensions/app-basic/tree/apache)
50-
[![Nginx](https://img.shields.io/badge/nginx-%23009639.svg?style=for-the-badge&logo=nginx&logoColor=white)](https://github.com/yii2-extensions/app-basic/tree/nginx)
51-
52-
### High-Performance Worker Mode
53-
54-
Long-running PHP workers for higher throughput and lower latency.
55-
56-
[![FrankenPHP](https://img.shields.io/badge/FrankenPHP-777BB4?style=for-the-badge&logo=php&logoColor=white)](https://github.com/yii2-extensions/app-basic/tree/franken-php)
57-
[![RoadRunner](https://img.shields.io/badge/RoadRunner-%23FF6B35.svg?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyIDJMMjIgMTJMMTIgMjJMMiAxMkwxMiAyWiIgZmlsbD0iI0ZGRkZGRiIvPgo8cGF0aCBkPSJNOCAyTDE2IDEwTDggMThaIiBmaWxsPSIjRkY2QjM1Ii8+CjxwYXRoIGQ9Ik0xNiA2TDIwIDEwTDE2IDE0WiIgZmlsbD0iI0ZGNkIzNSIvPgo8L3N2Zz4K&logoColor=white)](https://github.com/yii2-extensions/app-basic/tree/road-runner)
58-
59-
> For setup instructions, see `README.md` in each branch.
60-
6143
## How it works
6244

6345
The Yii2 Web Application Basic template provides a complete foundation for building modern web applications. Unlike starting from scratch, this template includes.
@@ -154,14 +136,13 @@ final class SiteController extends Controller
154136

155137
## Package information
156138

157-
[![Latest Stable Version](https://img.shields.io/packagist/v/yii2-extensions/app-basic.svg?style=for-the-badge&logo=packagist&logoColor=white&label=Stable)](https://packagist.org/packages/yii2-extensions/app-basic)
158-
[![Total Downloads](https://img.shields.io/packagist/dt/yii2-extensions/app-basic.svg?style=for-the-badge&logo=packagist&logoColor=white&label=Downloads)](https://packagist.org/packages/yii2-extensions/app-basic)
139+
[![Development Status](https://img.shields.io/badge/Status-Dev-orange.svg?style=for-the-badge&logo=packagist&logoColor=white)](https://github.com/yii2-extensions/app-basic/tree/franken-php-classic)
159140

160141
## Quality code
161142

162143
[![Codecov](https://img.shields.io/codecov/c/github/yii2-extensions/app-basic.svg?branch=main&style=for-the-badge&logo=codecov&logoColor=white&label=Coverage)](https://codecov.io/github/yii2-extensions/app-basic)
163-
[![PHPStan Level Max](https://img.shields.io/badge/PHPStan-Level%20Max-4F5D95.svg?style=for-the-badge&logo=php&logoColor=white)](https://github.com/yii2-extensions/app-basic/actions/workflows/static.yml)
164-
[![StyleCI](https://img.shields.io/badge/StyleCI-Passed-44CC11.svg?style=for-the-badge&logo=styleci&logoColor=white)](https://github.styleci.io/repos/165419144?branch=main)
144+
[![PHPStan Level Max](https://img.shields.io/badge/PHPStan-Level%20Max-4F5D95.svg?style=for-the-badge&logo=php&logoColor=white)](https://github.com/yii2-extensions/app-basic/actions/workflows/static.yml?query=branch%3Afranken-php-classic)
145+
[![StyleCI](https://img.shields.io/badge/StyleCI-Passed-44CC11.svg?style=for-the-badge&logo=styleci&logoColor=white)](https://github.styleci.io/repos/165419144?branch=franken-php-classic)
165146

166147
## Documentation
167148

codeception.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ paths:
66
output: runtime/output
77
data: tests/Support/data
88
support: tests/Support
9-
envs: tests/_envs
109
actor_suffix: Tester
1110
settings:
1211
memory_limit: 1024M

docker-compose.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
services:
2+
yii2-frankenphp:
3+
build:
4+
args:
5+
USER_ID: ${USER_ID:-1000}
6+
GROUP_ID: ${GROUP_ID:-1000}
7+
USER_NAME: ${USER_NAME:-www-data}
8+
GROUP_NAME: ${GROUP_NAME:-www-data}
9+
context: .
10+
dockerfile: docker/frankenphp/Dockerfile
11+
container_name: yii2-frankenphp
12+
entrypoint: ["/usr/local/bin/entrypoint.sh"]
13+
env_file:
14+
- .env
15+
environment:
16+
TZ: "UTC"
17+
YII_DEBUG: "${YII_DEBUG:-false}"
18+
YII_ENV: "${YII_ENV:-prod}"
19+
ports:
20+
- '8080:80'
21+
- '8443:443'
22+
- '8443:443/udp'
23+
restart: always
24+
tty: true
25+
volumes:
26+
- ./:/app
27+
- caddy_config:/config
28+
- caddy_data:/data
29+
- composer_cache:/var/www/.composer/cache
30+
working_dir: /app
31+
32+
volumes:
33+
caddy_data:
34+
caddy_config:
35+
composer_cache:

docker/entrypoint.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
echo "=== Container Starting ==="
5+
echo "Running initialization script..."
6+
7+
# Ensure init script is executable
8+
chmod +x /usr/local/bin/init.sh
9+
10+
# Execute init script; replace the PID 1 shell
11+
exec /usr/local/bin/init.sh
12+
13+
# If we get here, everything went well
14+
echo "=== Container ready ==="

docker/frankenphp/Caddyfile

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
# Global options
3+
auto_https off
4+
}
5+
6+
# HTTPS server block using mkcert certificates
7+
https://localhost:443 {
8+
# Specify mkcert certificates
9+
tls /app/docker/ssl/localhost.pem /app/docker/ssl/localhost-key.pem
10+
11+
# Document root
12+
root * /app/web
13+
14+
# Enable PHP processing with FrankenPHP
15+
php_server
16+
17+
# Security headers
18+
header {
19+
X-Frame-Options "SAMEORIGIN"
20+
X-XSS-Protection "1; mode=block"
21+
X-Content-Type-Options "nosniff"
22+
Strict-Transport-Security "max-age=31536000; includeSubDomains"
23+
-Server
24+
}
25+
26+
# Logging
27+
log {
28+
output stdout
29+
format console
30+
}
31+
32+
# Handle static files
33+
@static {
34+
file
35+
path *.css *.js *.png *.jpg *.jpeg *.gif *.ico *.svg *.woff *.woff2 *.ttf *.eot
36+
}
37+
handle @static {
38+
header Cache-Control "public, max-age=31536000"
39+
file_server
40+
}
41+
42+
# Block access to sensitive directories
43+
@forbidden {
44+
path /.git/* /vendor/* /runtime/* /.env*
45+
}
46+
respond @forbidden 404
47+
48+
# Deny PHP execution in assets directory (Yii2 security)
49+
@assets_php {
50+
path /assets/*.php
51+
}
52+
respond @assets_php 403
53+
54+
# Try files for Yii2 URL rewriting
55+
try_files {path} {path}/ /index.php?{query}
56+
}
57+
58+
# HTTP server block - redirect to HTTPS
59+
http://localhost:80 {
60+
# Redirect all HTTP traffic to HTTPS
61+
redir https://localhost:8443{uri} permanent
62+
}

docker/frankenphp/Dockerfile

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
FROM dunglas/frankenphp:1.8-php8.4
2+
3+
# Build arguments for user/group
4+
ARG USER_ID=1000
5+
ARG GROUP_ID=1000
6+
ARG USER_NAME=www-data
7+
ARG GROUP_NAME=www-data
8+
9+
# Change web server config
10+
COPY docker/frankenphp/Caddyfile /etc/caddy/Caddyfile
11+
12+
# Set document root to /app/web (Yii2 structure)
13+
WORKDIR /app
14+
15+
# Install required system packages for PHP extensions for Yii 2.0 Framework
16+
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
17+
RUN install-php-extensions \
18+
bcmath \
19+
@composer \
20+
exif \
21+
gd \
22+
imagick \
23+
intl \
24+
opcache \
25+
pdo_mysql \
26+
pdo_pgsql \
27+
soap \
28+
xdebug \
29+
zip
30+
31+
# Set composer environment
32+
ENV COMPOSER_ALLOW_SUPERUSER=1
33+
34+
# Change PHP config
35+
COPY docker/php/php.ini /usr/local/etc/php/conf.d/base.ini
36+
37+
# Install supervisor, gosu, and Node.js (version simple)
38+
RUN apt-get update && apt-get install -y --no-install-recommends \
39+
supervisor \
40+
curl \
41+
gosu \
42+
&& curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
43+
&& apt-get install -y nodejs \
44+
&& apt-get clean \
45+
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
46+
47+
# Apply the user/group IDs to www-data
48+
RUN usermod -u ${USER_ID} www-data && groupmod -g ${GROUP_ID} www-data
49+
50+
# Create composer and npm cache directories with proper ownership
51+
RUN mkdir -p /var/www/.composer/cache /var/www/.npm && \
52+
chown -R www-data:www-data /var/www/.composer /var/www/.npm
53+
54+
# Copy supervisor program configs
55+
COPY docker/supervisor/conf.d/frankenphp.conf /etc/supervisor/conf.d/frankenphp.conf
56+
57+
# Copy queue worker config uncommented for use with yii2-queue
58+
#COPY docker/supervisor/conf.d/queue.conf /etc/supervisor/conf.d/queue.conf
59+
60+
# Copy scripts
61+
COPY docker/init.sh /usr/local/bin/init.sh
62+
COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
63+
64+
# Make scripts executable and validate
65+
RUN chmod +x /usr/local/bin/init.sh /usr/local/bin/entrypoint.sh && \
66+
# Convert any Windows line endings
67+
sed -i 's/\r$//' /usr/local/bin/init.sh /usr/local/bin/entrypoint.sh && \
68+
# Test that scripts have valid syntax
69+
bash -n /usr/local/bin/init.sh && \
70+
bash -n /usr/local/bin/entrypoint.sh && \
71+
echo "✓ Scripts validated successfully..."
72+
73+
# Use ENTRYPOINT to guarantee execution
74+
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

docker/init.sh

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#!/bin/bash
2+
3+
# Colors for output
4+
RED='\033[0;31m'
5+
GREEN='\033[0;32m'
6+
YELLOW='\033[1;33m'
7+
NC='\033[0m'
8+
9+
echo -e "${GREEN}Starting container setup...${NC}"
10+
11+
# Create necessary Caddy directories with proper permissions
12+
echo -e "${YELLOW}Creating Caddy directories...${NC}"
13+
mkdir -p /data/caddy/locks /config/caddy
14+
chown -R www-data:www-data /data /config
15+
chmod -R 755 /data /config
16+
17+
# Create necessary Yii2 directories if they don't exist
18+
echo -e "${YELLOW}Creating Yii2 directories...${NC}"
19+
mkdir -p /app/runtime/cache
20+
mkdir -p /app/runtime/logs
21+
mkdir -p /app/web/assets
22+
23+
# Configure permissions for Yii2 directories
24+
echo -e "${YELLOW}Setting up permissions...${NC}"
25+
26+
# Try to set permissions and ownership - handle both mounted volumes and container-only scenarios
27+
if chown -R www-data:www-data /app/runtime 2>/dev/null; then
28+
chmod -R 775 /app/runtime
29+
echo -e "${GREEN}✓ Runtime directory configured correctly${NC}"
30+
else
31+
# If chown fails (mounted volume), try chmod only
32+
if chmod -R 777 /app/runtime 2>/dev/null; then
33+
echo -e "${YELLOW}⚠ Runtime directory permissions set to 777 (mounted volume)${NC}"
34+
else
35+
echo -e "${RED}✗ Error: Could not configure runtime directory${NC}"
36+
fi
37+
fi
38+
39+
if chown -R www-data:www-data /app/web/assets 2>/dev/null; then
40+
chmod -R 775 /app/web/assets
41+
echo -e "${GREEN}✓ Assets directory configured correctly${NC}"
42+
else
43+
# If chown fails (mounted volume), try chmod only
44+
if chmod -R 777 /app/web/assets 2>/dev/null; then
45+
echo -e "${YELLOW}⚠ Assets directory permissions set to 777 (mounted volume)${NC}"
46+
else
47+
echo -e "${RED}✗ Error: Could not configure assets directory${NC}"
48+
fi
49+
fi
50+
51+
echo -e "${GREEN}Setup completed.${NC}"
52+
53+
# Check if composer.json exists and vendor directory doesn't exist
54+
if [ -f "/app/composer.json" ] && [ ! -d "/app/vendor" ]; then
55+
echo -e "${YELLOW}Installing Composer dependencies...${NC}"
56+
57+
# Give www-data write access without exposing the tree to everyone
58+
chown -R www-data:www-data /app && \
59+
chmod -R u+rwX,g+rwX /app
60+
61+
# Create and configure npm cache directory for www-data
62+
mkdir -p /var/www/.npm
63+
chown -R www-data:www-data /var/www/.npm
64+
65+
# Install dependencies with proper environment variables
66+
if [ "$YII_ENV" = "prod" ]; then
67+
# Production: exclude dev dependencies and optimize autoloader
68+
gosu www-data env \
69+
HOME=/var/www \
70+
COMPOSER_HOME=/var/www/.composer \
71+
COMPOSER_CACHE_DIR=/var/www/.composer/cache \
72+
npm_config_cache=/var/www/.npm \
73+
composer install --no-dev --optimize-autoloader --no-interaction
74+
else
75+
# Development: include dev dependencies
76+
gosu www-data env \
77+
HOME=/var/www \
78+
COMPOSER_HOME=/var/www/.composer \
79+
COMPOSER_CACHE_DIR=/var/www/.composer/cache \
80+
npm_config_cache=/var/www/.npm \
81+
composer install --optimize-autoloader --no-interaction
82+
fi
83+
84+
echo -e "${GREEN}✓ Composer dependencies installed successfully${NC}"
85+
fi
86+
87+
# Copy supervisor configuration
88+
echo -e "${YELLOW}Configuring supervisor...${NC}"
89+
90+
if [ -f "/app/docker/supervisor/supervisord.conf" ]; then
91+
cp /app/docker/supervisor/supervisord.conf /etc/supervisor/supervisord.conf
92+
echo -e "${GREEN}✓ Supervisor configuration copied successfully${NC}"
93+
else
94+
echo -e "${RED}✗ Error: Supervisor configuration file not found${NC}"
95+
exit 1
96+
fi
97+
98+
echo -e "${GREEN}Starting supervisor daemon...${NC}"
99+
100+
# Start supervisor daemon
101+
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf

0 commit comments

Comments
 (0)