Compare commits
No commits in common. "dev" and "main" have entirely different histories.
19 changed files with 76 additions and 732 deletions
|
|
@ -1,13 +0,0 @@
|
|||
# CodeRabbit Configuration
|
||||
# Inherits from: https://github.com/host-uk/coderabbit/.coderabbit.yaml
|
||||
|
||||
reviews:
|
||||
review_status: false
|
||||
|
||||
path_instructions:
|
||||
- path: "**/Dockerfile*"
|
||||
instructions: "Check for security best practices, multi-stage builds, and pinned versions"
|
||||
- path: "**/*.yml"
|
||||
instructions: "Ansible/Docker Compose - validate syntax and idempotency"
|
||||
- path: "**/*.sh"
|
||||
instructions: "Shell scripts - check for shellcheck compliance and proper error handling"
|
||||
143
.github/workflows/build.yml
vendored
143
.github/workflows/build.yml
vendored
|
|
@ -1,24 +1,15 @@
|
|||
# Host UK Container Images
|
||||
#
|
||||
# Dev branch: ghcr.io/host-uk/{core-dev,server-php}:dev
|
||||
# Tags/Main: ghcr.io/host-uk/{core-dev,server-php}:latest + lthn/{core-dev,server-php}:latest
|
||||
|
||||
name: Build Images
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [dev, main]
|
||||
branches: [main]
|
||||
tags: ['v*']
|
||||
pull_request:
|
||||
branches: [dev, main]
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
GHCR_REGISTRY: ghcr.io
|
||||
REGISTRY: ghcr.io
|
||||
|
||||
jobs:
|
||||
# ============================================================
|
||||
|
|
@ -32,18 +23,10 @@ jobs:
|
|||
packages: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image:
|
||||
- developer
|
||||
- server-php
|
||||
include:
|
||||
- image: developer
|
||||
ghcr_name: core-dev
|
||||
dockerhub_name: core-dev
|
||||
- image: server-php
|
||||
ghcr_name: server-php
|
||||
dockerhub_name: server-php
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
|
@ -59,57 +42,21 @@ jobs:
|
|||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.GHCR_REGISTRY }}
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Determine if release build
|
||||
id: release
|
||||
run: |
|
||||
if [[ "${{ github.ref }}" == "refs/heads/main" ]] || [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||
echo "is_release=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "is_release=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Extract metadata (GHCR only - dev builds)
|
||||
if: steps.release.outputs.is_release == 'false'
|
||||
id: meta-dev
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.GHCR_REGISTRY }}/host-uk/${{ matrix.ghcr_name }}
|
||||
images: ${{ env.REGISTRY }}/host-uk/${{ matrix.image == 'developer' && 'core-dev' || matrix.image }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
flavor: |
|
||||
latest=false
|
||||
|
||||
- name: Extract metadata (GHCR + Docker Hub - release builds)
|
||||
if: steps.release.outputs.is_release == 'true'
|
||||
id: meta-release
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.GHCR_REGISTRY }}/host-uk/${{ matrix.ghcr_name }}
|
||||
lthn/${{ matrix.dockerhub_name }}
|
||||
tags: |
|
||||
# main branch -> latest
|
||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
# Semver tags (v1.0.0 -> 1.0.0, 1.0, 1, latest)
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
|
||||
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
flavor: |
|
||||
latest=false
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
|
|
@ -117,64 +64,62 @@ jobs:
|
|||
context: ./${{ matrix.image }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta-dev.outputs.tags || steps.meta-release.outputs.tags }}
|
||||
labels: ${{ steps.meta-dev.outputs.labels || steps.meta-release.outputs.labels }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
# ============================================================
|
||||
# Build LinuxKit Images (only on tags)
|
||||
# Build LinuxKit Images
|
||||
# ============================================================
|
||||
linuxkit:
|
||||
name: LinuxKit (${{ matrix.image }}-${{ matrix.arch }})
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
needs: docker # Needs Docker images to be built first
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [developer, server-php]
|
||||
arch: [amd64, arm64]
|
||||
format: [qcow2-bios, iso-bios]
|
||||
include:
|
||||
- image: developer
|
||||
output_name: core-dev
|
||||
- image: server-php
|
||||
output_name: server-php
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install LinuxKit
|
||||
- name: Install Core CLI
|
||||
run: |
|
||||
curl -fsSL "https://github.com/linuxkit/linuxkit/releases/download/v1.5.3/linuxkit-linux-amd64" -o linuxkit
|
||||
chmod +x linuxkit
|
||||
sudo mv linuxkit /usr/local/bin/
|
||||
# Download latest core binary
|
||||
curl -fsSL "https://github.com/host-uk/core/releases/latest/download/core-linux-amd64.tar.gz" -o core.tar.gz
|
||||
tar -xzf core.tar.gz
|
||||
sudo mv core /usr/local/bin/core
|
||||
chmod +x /usr/local/bin/core
|
||||
core --version
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Login to GHCR
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.GHCR_REGISTRY }}
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build LinuxKit Image
|
||||
run: |
|
||||
mkdir -p dist
|
||||
linuxkit build \
|
||||
core build --type linuxkit \
|
||||
--config ./${{ matrix.image }}/linuxkit.yml \
|
||||
--format ${{ matrix.format }} \
|
||||
--name ./dist/${{ matrix.output_name }}-${{ matrix.arch }} \
|
||||
./${{ matrix.image }}/linuxkit.yml
|
||||
--arch ${{ matrix.arch }} \
|
||||
-o ./dist/${{ matrix.image == 'developer' && 'core-dev' || matrix.image }}-${{ matrix.arch }}
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.output_name }}-${{ matrix.arch }}-${{ matrix.format }}
|
||||
name: ${{ matrix.image == 'developer' && 'core-dev' || matrix.image }}-${{ matrix.arch }}-${{ matrix.format }}
|
||||
path: ./dist/*
|
||||
|
||||
# ============================================================
|
||||
|
|
@ -207,3 +152,39 @@ jobs:
|
|||
dist/*
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# ============================================================
|
||||
# Build TIM Bundles (when core build --type tim is ready)
|
||||
# ============================================================
|
||||
# tim:
|
||||
# name: TIM (${{ matrix.image }})
|
||||
# runs-on: ubuntu-latest
|
||||
# needs: docker
|
||||
#
|
||||
# strategy:
|
||||
# matrix:
|
||||
# image: [developer, server-php]
|
||||
# os: [linux, darwin]
|
||||
# arch: [amd64, arm64]
|
||||
#
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
#
|
||||
# - name: Install Core
|
||||
# run: |
|
||||
# curl -fsSL https://github.com/host-uk/core/releases/latest/download/core-linux-amd64 -o /usr/local/bin/core
|
||||
# chmod +x /usr/local/bin/core
|
||||
#
|
||||
# - name: Build TIM
|
||||
# run: |
|
||||
# core build --type tim \
|
||||
# --borgfile ./${{ matrix.image }}/Borgfile \
|
||||
# --os ${{ matrix.os }} \
|
||||
# --arch ${{ matrix.arch }} \
|
||||
# -o ./dist/${{ matrix.image }}-${{ matrix.os }}-${{ matrix.arch }}.tim
|
||||
#
|
||||
# - name: Upload artifact
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: ${{ matrix.image }}-${{ matrix.os }}-${{ matrix.arch }}
|
||||
# path: ./dist/*.tim
|
||||
|
|
|
|||
|
|
@ -25,9 +25,6 @@ ENV LC_ALL=C.UTF-8
|
|||
ENV TERM=xterm-256color
|
||||
ENV EDITOR=nvim
|
||||
ENV SHELL=/bin/zsh
|
||||
ENV CODEX_HOME=/root/.codex
|
||||
ENV CORE_DEV_HOST_HOME=/host-home
|
||||
ENV CODEX_AUTH_SYNC=1
|
||||
ENV GOPATH=/root/go
|
||||
ENV CARGO_HOME=/root/.cargo
|
||||
ENV RUSTUP_HOME=/root/.rustup
|
||||
|
|
@ -68,9 +65,8 @@ RUN apk add --no-cache \
|
|||
# ============================================================
|
||||
# VCS & Git Tools
|
||||
# ============================================================
|
||||
# Note: git-delta not in Alpine repos, install via cargo if needed
|
||||
RUN apk add --no-cache \
|
||||
git git-lfs github-cli lazygit
|
||||
git git-lfs github-cli lazygit git-delta
|
||||
|
||||
# ============================================================
|
||||
# Node.js Ecosystem
|
||||
|
|
@ -127,13 +123,13 @@ RUN ln -sf /usr/bin/php84 /usr/bin/php
|
|||
RUN curl -sS https://getcomposer.org/installer | php -- \
|
||||
--install-dir=/usr/bin --filename=composer
|
||||
|
||||
# Allow Pest plugin and install PHP tools globally
|
||||
RUN composer global config allow-plugins.pestphp/pest-plugin true && \
|
||||
composer global require --no-interaction \
|
||||
# PHP tools via Composer
|
||||
RUN composer global require --no-interaction \
|
||||
phpunit/phpunit:^11.0 \
|
||||
pestphp/pest:^3.0 \
|
||||
phpstan/phpstan:^2.0 \
|
||||
laravel/pint:^1.0
|
||||
laravel/pint:^1.0 \
|
||||
phpdocumentor/phpdocumentor:^3.0
|
||||
|
||||
# FrankenPHP (static binary)
|
||||
RUN curl -fsSL "https://github.com/dunglas/frankenphp/releases/latest/download/frankenphp-linux-$(uname -m | sed 's/aarch64/arm64/' | sed 's/x86_64/x86_64/')" -o /usr/local/bin/frankenphp && \
|
||||
|
|
@ -144,13 +140,12 @@ RUN curl -fsSL "https://github.com/dunglas/frankenphp/releases/latest/download/f
|
|||
# ============================================================
|
||||
RUN apk add --no-cache go
|
||||
|
||||
# Note: Some tools require newer Go versions, so we pin compatible versions
|
||||
# or make installations optional with || true
|
||||
RUN go install golang.org/x/tools/gopls@v0.17.1 || true && \
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2 && \
|
||||
go install github.com/go-task/task/v3/cmd/task@v3.40.1 && \
|
||||
go install github.com/casey/just@latest || true && \
|
||||
go install github.com/boyter/scc/v3@v3.4.0 || true
|
||||
RUN go install golang.org/x/tools/gopls@latest && \
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest && \
|
||||
go install github.com/go-task/task/v3/cmd/task@latest && \
|
||||
go install github.com/casey/just@latest && \
|
||||
go install github.com/watchexec/watchexec/cmd/watchexec@latest 2>/dev/null || true && \
|
||||
go install github.com/boyter/scc/v3@latest
|
||||
|
||||
# ============================================================
|
||||
# Rust Ecosystem
|
||||
|
|
@ -286,7 +281,7 @@ COPY --chmod=644 config/aliases.sh /etc/profile.d/aliases.sh
|
|||
COPY --chmod=755 scripts/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
|
||||
# Create directories
|
||||
RUN mkdir -p /root/.config /root/.claude /root/.codex /workspace
|
||||
RUN mkdir -p /root/.config /root/.claude /workspace
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
|
|
|
|||
|
|
@ -3,28 +3,6 @@
|
|||
|
||||
set -e
|
||||
|
||||
sync_dir() {
|
||||
src="$1"
|
||||
dst="$2"
|
||||
|
||||
if [ ! -d "$src" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p "$dst"
|
||||
# Copy host state into container state each boot so auth/extensions are portable.
|
||||
cp -a "$src"/. "$dst"/
|
||||
}
|
||||
|
||||
# Sync Codex auth/state from host profile if mounted.
|
||||
# Example: -v "$HOME:/host-home:ro"
|
||||
if [ "${CODEX_AUTH_SYNC:-1}" = "1" ]; then
|
||||
HOST_HOME="${CORE_DEV_HOST_HOME:-/host-home}"
|
||||
HOST_CODEX_HOME="${HOST_HOME}/.codex"
|
||||
CONTAINER_CODEX_HOME="${CODEX_HOME:-${HOME}/.codex}"
|
||||
sync_dir "$HOST_CODEX_HOME" "$CONTAINER_CODEX_HOME"
|
||||
fi
|
||||
|
||||
# Run pre-start hooks if they exist
|
||||
if [ -d "/root/.config/core-dev/hooks/pre-start" ]; then
|
||||
for hook in /root/.config/core-dev/hooks/pre-start/*; do
|
||||
|
|
@ -48,8 +26,8 @@ fi
|
|||
# Setup SSH agent if keys exist
|
||||
if [ -d "$HOME/.ssh" ] && [ -z "$SSH_AUTH_SOCK" ]; then
|
||||
eval "$(ssh-agent -s)" > /dev/null 2>&1
|
||||
for key in "$HOME"/.ssh/id_*; do
|
||||
[ -f "$key" ] && [ ! -f "$key.pub" ] && ssh-add "$key" 2>/dev/null || true
|
||||
for key in $HOME/.ssh/id_* ; do
|
||||
[ -f "$key" ] && [ ! -f "$key.pub" ] || ssh-add "$key" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -1,182 +0,0 @@
|
|||
# Unified nginx configuration
|
||||
# Routes traffic based on domain:
|
||||
# - host.uk.com → Laravel Host Hub (PHP-FPM)
|
||||
# - *.host.uk.com → WordPress (PHP-FPM)
|
||||
|
||||
# Map for allowed CORS origins (WordPress REST API)
|
||||
map $http_origin $cors_origin {
|
||||
default "";
|
||||
"~^https?://host\.uk\.com$" $http_origin;
|
||||
"~^https?://social\.host\.uk\.com$" $http_origin;
|
||||
"~^https?://link\.host\.uk\.com$" $http_origin;
|
||||
"~^https?://analytics\.host\.uk\.com$" $http_origin;
|
||||
"~^https?://trust\.host\.uk\.com$" $http_origin;
|
||||
"~^https?://notify\.host\.uk\.com$" $http_origin;
|
||||
"~^https?://localhost(:[0-9]+)?$" $http_origin;
|
||||
"~^https?://127\.0\.0\.1(:[0-9]+)?$" $http_origin;
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# LARAVEL HOST HUB - Apex Domain
|
||||
# ============================================
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name host.uk.com www.host.uk.com;
|
||||
|
||||
root /app/public;
|
||||
index index.php;
|
||||
|
||||
client_max_body_size 64M;
|
||||
|
||||
# Security headers
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Health check - returns 200 if nginx is up (no PHP needed)
|
||||
location = /healthz {
|
||||
access_log off;
|
||||
add_header Content-Type text/plain;
|
||||
return 200 "ok\n";
|
||||
}
|
||||
|
||||
# WordPress REST API proxy
|
||||
# host.uk.com/api/wordpress/* → WordPress /wp-json/*
|
||||
# Same-origin, no CORS needed
|
||||
location ~ ^/api/wordpress/(.*)$ {
|
||||
# Pass to WordPress index.php with rest_route
|
||||
fastcgi_pass unix:/run/php-fpm.sock;
|
||||
fastcgi_param SCRIPT_FILENAME /var/www/html/index.php;
|
||||
fastcgi_param REQUEST_URI /wp-json/$1$is_args$args;
|
||||
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_buffering off;
|
||||
fastcgi_read_timeout 300;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# Laravel routing
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# PHP-FPM for Laravel
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass unix:/run/php-fpm.sock;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_buffering off;
|
||||
fastcgi_read_timeout 300;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# Livewire and Flux - must go to Laravel (not static files)
|
||||
location ~ ^/(admin|flux)/ {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# Laravel static assets (build, vendor directories only)
|
||||
location ~* ^/(build|vendor)/.*\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires max;
|
||||
add_header Cache-Control "public, immutable";
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Deny hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
|
||||
# PHP-FPM status (internal only)
|
||||
location ~ ^/(fpm-status|fpm-ping)$ {
|
||||
access_log off;
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
fastcgi_pass unix:/run/php-fpm.sock;
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================
|
||||
# LARAVEL SATELLITES - Subdomains
|
||||
# ============================================
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name *.host.uk.com;
|
||||
|
||||
root /app/public;
|
||||
index index.php;
|
||||
|
||||
client_max_body_size 64M;
|
||||
|
||||
# Security headers
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Health check
|
||||
location = /healthz {
|
||||
access_log off;
|
||||
add_header Content-Type text/plain;
|
||||
return 200 "ok\n";
|
||||
}
|
||||
|
||||
# WordPress REST API (for internal content sync)
|
||||
# Routes /wp-json/* requests to WordPress
|
||||
# Host header determines which multisite blog to serve
|
||||
location ~ ^/wp-json/(.*)$ {
|
||||
fastcgi_pass unix:/run/php-fpm.sock;
|
||||
fastcgi_param SCRIPT_FILENAME /var/www/html/index.php;
|
||||
fastcgi_param REQUEST_URI /wp-json/$1$is_args$args;
|
||||
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_buffering off;
|
||||
fastcgi_read_timeout 300;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# Laravel routing
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# PHP-FPM for Laravel
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass unix:/run/php-fpm.sock;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_buffering off;
|
||||
fastcgi_read_timeout 300;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# Livewire and Flux
|
||||
location ~ ^/(admin|flux)/ {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# Static assets
|
||||
location ~* ^/(build|vendor)/.*\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires max;
|
||||
add_header Cache-Control "public, immutable";
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Deny hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
# WordPress Multisite server configuration
|
||||
# Map for allowed CORS origins
|
||||
map $http_origin $cors_origin {
|
||||
default "";
|
||||
"~^https?://host\.uk\.com$" $http_origin;
|
||||
"~^https?://social\.host\.uk\.com$" $http_origin;
|
||||
"~^https?://link\.host\.uk\.com$" $http_origin;
|
||||
"~^https?://analytics\.host\.uk\.com$" $http_origin;
|
||||
"~^https?://trust\.host\.uk\.com$" $http_origin;
|
||||
"~^https?://notify\.host\.uk\.com$" $http_origin;
|
||||
"~^https?://localhost(:[0-9]+)?$" $http_origin;
|
||||
"~^https?://127\.0\.0\.1(:[0-9]+)?$" $http_origin;
|
||||
}
|
||||
|
||||
server {
|
||||
listen [::]:80 default_server;
|
||||
listen 80 default_server;
|
||||
|
||||
# Only accept subdomain traffic (*.host.uk.com), not apex domain
|
||||
# The apex domain (host.uk.com) should route to Host Hub (Laravel)
|
||||
server_name ~^(?<subdomain>.+)\.host\.uk\.com$ hestia.host.uk.com *.host.uk.com;
|
||||
|
||||
# Serve error page for apex domain - this shouldn't hit WordPress
|
||||
# If it does, Coolify routing is misconfigured
|
||||
error_page 503 /wp-content/routing-error.html;
|
||||
if ($host = "host.uk.com") {
|
||||
return 503;
|
||||
}
|
||||
|
||||
# Reject completely unknown hosts with connection close
|
||||
if ($host !~ "\.host\.uk\.com$") {
|
||||
return 444;
|
||||
}
|
||||
|
||||
sendfile off;
|
||||
tcp_nodelay on;
|
||||
absolute_redirect off;
|
||||
|
||||
root /var/www/html;
|
||||
index index.php;
|
||||
|
||||
client_max_body_size 64M;
|
||||
|
||||
# Security headers
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# WordPress multisite rewrite rules
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$args;
|
||||
}
|
||||
|
||||
# REST API with CORS headers for headless operation
|
||||
location /wp-json/ {
|
||||
# Handle preflight OPTIONS requests
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header 'Access-Control-Allow-Origin' $cors_origin always;
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE, OPTIONS' always;
|
||||
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-WP-Nonce' always;
|
||||
add_header 'Access-Control-Allow-Credentials' 'true' always;
|
||||
add_header 'Access-Control-Max-Age' 86400 always;
|
||||
add_header 'Content-Length' 0;
|
||||
add_header 'Content-Type' 'text/plain';
|
||||
return 204;
|
||||
}
|
||||
|
||||
# Add CORS headers to actual requests
|
||||
add_header 'Access-Control-Allow-Origin' $cors_origin always;
|
||||
add_header 'Access-Control-Allow-Credentials' 'true' always;
|
||||
add_header 'Access-Control-Expose-Headers' 'X-WP-Total, X-WP-TotalPages, Link' always;
|
||||
|
||||
try_files $uri $uri/ /index.php?$args;
|
||||
}
|
||||
|
||||
# Pass the PHP scripts to PHP-FPM listening on unix socket
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass unix:/run/php-fpm.sock;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_buffering off;
|
||||
fastcgi_read_timeout 300;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires max;
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location = /favicon.ico {
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location = /robots.txt {
|
||||
allow all;
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Block XML-RPC by default, allow with secret token
|
||||
# Usage: /xmlrpc.php?token=YOUR_XMLRPC_TOKEN
|
||||
location = /xmlrpc.php {
|
||||
set $xmlrpc_allowed 0;
|
||||
|
||||
# Allow if valid token provided (set in environment or change here)
|
||||
if ($arg_token = "xrpc-9f8e7d6c5b4a") {
|
||||
set $xmlrpc_allowed 1;
|
||||
}
|
||||
|
||||
# Block if no valid token
|
||||
if ($xmlrpc_allowed = 0) {
|
||||
return 403;
|
||||
}
|
||||
|
||||
# Pass to PHP if allowed
|
||||
try_files $uri =404;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass unix:/run/php-fpm.sock;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# Deny access to hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# Deny access to backup files
|
||||
location ~ ~$ {
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
deny all;
|
||||
}
|
||||
|
||||
# Allow fpm ping and status from localhost
|
||||
location ~ ^/(fpm-status|fpm-ping)$ {
|
||||
access_log off;
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
fastcgi_pass unix:/run/php-fpm.sock;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
[global]
|
||||
; Log to stderr
|
||||
error_log = /dev/stderr
|
||||
|
||||
[www]
|
||||
; User and group for PHP-FPM processes
|
||||
user = nobody
|
||||
group = nobody
|
||||
|
||||
; The address on which to accept FastCGI requests.
|
||||
listen = /run/php-fpm.sock
|
||||
|
||||
; Set permissions for unix socket
|
||||
listen.owner = nobody
|
||||
listen.group = nobody
|
||||
listen.mode = 0666
|
||||
|
||||
; Enable status page
|
||||
pm.status_path = /fpm-status
|
||||
|
||||
; Ondemand process manager
|
||||
pm = ondemand
|
||||
|
||||
; The maximum number of child processes
|
||||
pm.max_children = 100
|
||||
|
||||
; The number of seconds after which an idle process will be killed.
|
||||
pm.process_idle_timeout = 10s
|
||||
|
||||
; The number of requests each child process should execute before respawning.
|
||||
pm.max_requests = 1000
|
||||
|
||||
; Make sure the FPM workers can reach the environment variables for configuration
|
||||
clear_env = no
|
||||
|
||||
; Catch output from PHP
|
||||
catch_workers_output = yes
|
||||
|
||||
; Remove the 'child 10 said into stderr' prefix in the log and only show the actual message
|
||||
decorate_workers_output = no
|
||||
|
||||
; Enable ping page to use in healthcheck
|
||||
ping.path = /fpm-ping
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
# Production performance optimizations
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
|
||||
|
||||
# Brotli (if available)
|
||||
brotli on;
|
||||
brotli_comp_level 6;
|
||||
brotli_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
|
||||
|
||||
# Cache static files
|
||||
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
upstream php-fpm {
|
||||
server host-uk-dev-wordpress:9000;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /var/www/html;
|
||||
index index.php;
|
||||
|
||||
client_max_body_size 64M;
|
||||
|
||||
# Security headers
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$args;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass php-fpm;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
|
||||
fastcgi_buffering off;
|
||||
fastcgi_read_timeout 300;
|
||||
}
|
||||
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires max;
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location = /favicon.ico {
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location = /robots.txt {
|
||||
allow all;
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
location ~ ~$ {
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
[opcache]
|
||||
opcache.enable=1
|
||||
opcache.memory_consumption=256
|
||||
opcache.interned_strings_buffer=32
|
||||
opcache.max_accelerated_files=20000
|
||||
opcache.validate_timestamps=0
|
||||
opcache.save_comments=1
|
||||
opcache.enable_cli=1
|
||||
opcache.jit=1255
|
||||
opcache.jit_buffer_size=128M
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
; Development PHP settings
|
||||
display_errors = On
|
||||
display_startup_errors = On
|
||||
error_reporting = E_ALL
|
||||
log_errors = On
|
||||
|
||||
memory_limit = 512M
|
||||
max_execution_time = 300
|
||||
max_input_time = 300
|
||||
post_max_size = 128M
|
||||
upload_max_filesize = 128M
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
; Production PHP settings
|
||||
display_errors = Off
|
||||
display_startup_errors = Off
|
||||
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
|
||||
log_errors = On
|
||||
error_log = /var/log/php/error.log
|
||||
|
||||
memory_limit = 256M
|
||||
max_execution_time = 60
|
||||
max_input_time = 60
|
||||
post_max_size = 64M
|
||||
upload_max_filesize = 64M
|
||||
|
||||
expose_php = Off
|
||||
session.cookie_httponly = 1
|
||||
session.cookie_secure = 1
|
||||
session.use_strict_mode = 1
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
[Date]
|
||||
date.timezone="UTC"
|
||||
|
||||
[PHP]
|
||||
expose_php = Off
|
||||
upload_max_filesize = 64M
|
||||
post_max_size = 64M
|
||||
memory_limit = 256M
|
||||
max_execution_time = 300
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
[supervisord]
|
||||
nodaemon=true
|
||||
user=root
|
||||
logfile=/dev/null
|
||||
logfile_maxbytes=0
|
||||
pidfile=/run/supervisord.pid
|
||||
|
||||
[program:php-fpm]
|
||||
command=php-fpm84 -F
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
autorestart=false
|
||||
startretries=0
|
||||
|
||||
[program:nginx]
|
||||
command=nginx -g 'daemon off;'
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
autorestart=false
|
||||
startretries=0
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
[xdebug]
|
||||
xdebug.mode = develop,debug
|
||||
xdebug.start_with_request = trigger
|
||||
xdebug.client_host = host.docker.internal
|
||||
xdebug.client_port = 9003
|
||||
xdebug.idekey = PHPSTORM
|
||||
xdebug.log_level = 0
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
# Patch Directory
|
||||
|
||||
This directory contains files that override vendor packages after composer install.
|
||||
|
||||
## Usage
|
||||
|
||||
Place files here that should overwrite files in `vendor/` or elsewhere after dependencies are installed. The entire contents of this directory are copied over the application root.
|
||||
|
||||
## Example
|
||||
|
||||
To patch a vendor file:
|
||||
```
|
||||
patch/vendor/some-package/src/File.php
|
||||
```
|
||||
|
||||
This will overwrite `vendor/some-package/src/File.php` in the built image.
|
||||
|
||||
## Empty by Default
|
||||
|
||||
For the base image, this directory is empty. Applications using this image should mount or copy their own patches.
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"name": "host-uk/server-php-placeholder",
|
||||
"description": "Placeholder for base image",
|
||||
"type": "project",
|
||||
"require": {}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<?php
|
||||
// Placeholder for base image
|
||||
// Applications should mount/copy their own code
|
||||
echo json_encode([
|
||||
'status' => 'ok',
|
||||
'message' => 'Host UK Server PHP Base Image',
|
||||
'note' => 'Mount your Laravel app to /var/www/html'
|
||||
]);
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Install PHP dependencies if vendor directory is empty
|
||||
if [ ! -f "/app/vendor/autoload.php" ]; then
|
||||
echo "Installing PHP dependencies..."
|
||||
composer install --no-interaction --prefer-dist
|
||||
fi
|
||||
|
||||
# Install Node dependencies if node_modules is empty
|
||||
if [ ! -d "/app/node_modules" ] || [ -z "$(ls -A /app/node_modules 2>/dev/null)" ]; then
|
||||
echo "Installing Node dependencies..."
|
||||
npm install
|
||||
fi
|
||||
|
||||
# Run database migrations (skip errors if DB not ready)
|
||||
php artisan migrate --force 2>/dev/null || echo "Migrations skipped (DB may not be ready)"
|
||||
|
||||
# Execute the main command
|
||||
exec "$@"
|
||||
Loading…
Add table
Reference in a new issue