Refactor configuration handling: implement dynamic loading of config and cache paths for improved security and flexibility in Docker environments
This commit is contained in:
1 parent
c7b836bcf2
commit
bb65ecd43c
7 files changed
+53
-12
No files matched your search
+17
-4
@@ -5,10 +5,13 @@
|
||||
# docker-compose.yaml (this file)
|
||||
# .env (optional, see PROXY_NETWORK below)
|
||||
# www/ (contents of `npm run dist`)
|
||||
# data/ (fitz.sqlite — never inside www/)
|
||||
# config/config.php (live secrets — never inside www/, never in dist/)
|
||||
# data/ (fitz.sqlite + cache/ — never inside www/)
|
||||
#
|
||||
# First run: create data/ and `chown 33:33 data` (www-data in the image),
|
||||
# then create the first admin with bin/create-user.php (see its header).
|
||||
# First run: create data/ and `chown 33:33 data` (www-data in the image).
|
||||
# Copy config.example.php to config/config.php, fill it in, and make it
|
||||
# readable by www-data (`chown root:33` + `chmod 640`). Then create the
|
||||
# first admin with bin/create-user.php (see its header).
|
||||
#
|
||||
# The CasaOS dev host keeps its own copy of this file in the CasaOS app
|
||||
# settings, with CasaOS paths and its x-casaos block.
|
||||
@@ -43,13 +46,23 @@ services:
|
||||
- type: bind
|
||||
source: ./www
|
||||
target: /var/www/html
|
||||
# Database lives outside the web root so Apache can't serve it.
|
||||
# Database and cache live outside the web root so Apache can't serve
|
||||
# them and deploys to www/ never touch them.
|
||||
- type: bind
|
||||
source: ./data
|
||||
target: /var/www/data
|
||||
# Config is mounted as a directory, not a single file: a single-file
|
||||
# bind mount pins the inode, so an editor that saves by replacing the
|
||||
# file leaves the container reading the old copy until a restart.
|
||||
- type: bind
|
||||
source: ./config
|
||||
target: /var/www/config
|
||||
read_only: true
|
||||
environment:
|
||||
- TZ=America/Indiana/Indianapolis
|
||||
- FITZ_DB_PATH=/var/www/data/fitz.sqlite
|
||||
- FITZ_CACHE_DIR=/var/www/data/cache
|
||||
- FITZ_CONFIG_PATH=/var/www/config/config.php
|
||||
# Cap container logs so PHP's error log can't slowly fill the disk.
|
||||
logging:
|
||||
driver: json-file
|
||||
|
||||
@@ -20,7 +20,11 @@ function fritz_google_reviews(): array {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$cacheFile = __DIR__ . '/../cache/google-reviews.json';
|
||||
// In Docker, FITZ_CACHE_DIR points into the writable data/ mount, outside
|
||||
// the web root, so deploys don't wipe it and www/ can stay read-only to
|
||||
// www-data. Local dev falls back to cache/ in the project root.
|
||||
$cacheDir = getenv('FITZ_CACHE_DIR') ?: __DIR__ . '/../cache';
|
||||
$cacheFile = $cacheDir . '/google-reviews.json';
|
||||
|
||||
if (is_file($cacheFile)) {
|
||||
$cached = json_decode((string) file_get_contents($cacheFile), true);
|
||||
@@ -33,7 +37,6 @@ function fritz_google_reviews(): array {
|
||||
$fresh = fritz_fetch_google_reviews($fallback);
|
||||
$fresh['fetched_at'] = time();
|
||||
|
||||
$cacheDir = dirname($cacheFile);
|
||||
if (!is_dir($cacheDir)) {
|
||||
@mkdir($cacheDir, 0775, true);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Loads the site config. In Docker, FITZ_CONFIG_PATH points outside the
|
||||
* web root (see docker-compose.yaml), so a deploy that replaces www/ can
|
||||
* never overwrite or ship it. Local dev falls back to config.php in the
|
||||
* project root.
|
||||
*/
|
||||
|
||||
require getenv('FITZ_CONFIG_PATH') ?: __DIR__ . '/../config.php';
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
require __DIR__ . '/config.php';
|
||||
require __DIR__ . '/inc/load-config.php';
|
||||
require __DIR__ . '/inc/assets.php';
|
||||
require __DIR__ . '/inc/security-headers.php';
|
||||
send_security_headers();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/config.php';
|
||||
require __DIR__ . '/inc/load-config.php';
|
||||
require __DIR__ . '/inc/assets.php';
|
||||
require __DIR__ . '/inc/security-headers.php';
|
||||
send_security_headers();
|
||||
|
||||
@@ -6,9 +6,14 @@
|
||||
*
|
||||
* This is an allowlist by design: only the files and folders listed below
|
||||
* are copied. Dev-only stuff (node_modules/, src/, package*.json, .git/,
|
||||
* .claude/, docker-compose.yaml, dev.sh, .hintrc, config.example.php, the
|
||||
* live db/fitz.sqlite, ...) never ends up in dist/ — including anything
|
||||
* added later, since it has to be added here explicitly first.
|
||||
* .claude/, docker-compose.yaml, dev.sh, .hintrc, config.php,
|
||||
* config.example.php, the live db/fitz.sqlite, ...) never ends up in
|
||||
* dist/ — including anything added later, since it has to be added here
|
||||
* explicitly first.
|
||||
*
|
||||
* config.php is deliberately excluded: it holds live secrets and lives
|
||||
* outside the web root on the server (see FITZ_CONFIG_PATH in
|
||||
* docker-compose.yaml), so a deploy can never overwrite it.
|
||||
*
|
||||
* Run with: npm run dist
|
||||
*/
|
||||
@@ -25,7 +30,6 @@ const FILES = [
|
||||
'main.js',
|
||||
'styles.css',
|
||||
'robots.txt',
|
||||
'config.php', // holds the live FB_PAGE_ACCESS_TOKEN — see README before sharing dist/ anywhere but the server
|
||||
];
|
||||
|
||||
const DIRS = ['admin', 'assets', 'bin', 'inc'];
|
||||
|
||||
@@ -24,4 +24,14 @@ if (preg_match($blocked, $path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Apache (mod_dir) redirects /admin to /admin/; the built-in server just
|
||||
// serves admin/index.php at /admin. Every relative link on that page then
|
||||
// resolves against / instead of /admin/ — "menu.php" lands on the public
|
||||
// menu, "users.php" 404s. Match Apache so dev behaves like production.
|
||||
if ($path !== '/' && !str_ends_with($path, '/') && is_dir(__DIR__ . '/..' . $path)) {
|
||||
$query = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_QUERY);
|
||||
header('Location: ' . $path . '/' . ($query ? '?' . $query : ''), true, 301);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
Reference in new issue
Block a user