a0ae58c29e
Upload/browse/delete UI for files under public/uploads/, covered by the existing /admin/* auth gate with no separate feature flag needed (no SQLite dependency to gate). Extension allowlist and max upload size are configurable; filenames are sanitized and de-duplicated on upload, and deletes re-verify the resolved path lands inside the upload directory before touching disk. Docker gains a fourth-turned-third named volume for public/uploads/ so uploads survive a rebuild. images/ (reserved scaffolding for a future image feature) is removed — nothing ever consumed it, and public/uploads/ now covers that use case. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
46 lines
4.7 KiB
Twig
46 lines
4.7 KiB
Twig
{% extends 'admin/docs/_layout/layout.twig' %}
|
|
|
|
{% block title %}Docker{% endblock %}
|
|
|
|
{% block description %}Running novaconium in a container: the Apache/PHP image, its three volumes, and overriding App/ without a rebuild.{% endblock %}
|
|
|
|
{% block robots %}noindex, nofollow{% endblock %}
|
|
|
|
{% block docs_content %}
|
|
<h1>Docker</h1>
|
|
|
|
<p>The root <code>Dockerfile</code> builds an Apache + PHP image on an <a href="https://archlinux.org/">Arch Linux</a> base, with <code>mod_rewrite</code>, <code>AllowOverride All</code>, and <code>pdo_sqlite</code>/<code>pdo_mysql</code> already enabled — nothing else in <a href="/admin/docs/getting-started">Getting started</a>'s "Deploy on Apache" section needs configuring by hand. <code>docker-compose.yml</code> wires it up with three named volumes so a project's own cache, uploads, and database never live inside a path that gets wiped by the <a href="/admin/docs/getting-started">"Updating the framework"</a> workflow.</p>
|
|
|
|
<pre><code>docker compose up --build</code></pre>
|
|
|
|
<p>Visit <code>http://localhost:8080/</code>.</p>
|
|
|
|
<h2>The volumes</h2>
|
|
|
|
<ul>
|
|
<li><code>cache</code> → <code>public/cache/</code> — the static HTML page cache (see <a href="/admin/docs/caching">Static caching</a>). Disposable; clear it from inside the container with <code>docker compose exec web php novaconium/bin/clear-cache.php</code>.</li>
|
|
<li><code>uploads</code> → <code>public/uploads/</code> — files uploaded through <a class="icon-link" href="/admin/docs/media-manager">Media manager</a> (<code>/admin/media</code>). Needs its own volume specifically because <code>public/</code> is otherwise baked into the image with <code>COPY</code> at build time — without this, an upload would only survive until the next <code>docker compose up --build</code>. Kept separate from the <code>data</code> volume below deliberately, since a project might use MySQL or no database at all and shouldn't have upload storage coupled to the SQLite volume.</li>
|
|
<li><code>data</code> → <code>data/</code> — holds <code>data/novaconium.sqlite</code> if <a href="/admin/docs/database">Database</a>-backed features (admin auth, content index) are enabled. Persists across <code>docker compose down</code>/<code>up</code> as long as you don't pass <code>-v</code>.</li>
|
|
</ul>
|
|
|
|
<p><code>App/</code> itself is <strong>not</strong> a named volume — it's baked into the image with <code>COPY</code> at build time, so <code>docker compose up --build</code> alone produces a working site with no extra steps. A named volume seeded from <code>COPY App/</code> would only populate once, on first container creation, and would silently go stale on every later rebuild. To edit content without rebuilding, uncomment the bind mount in <code>docker-compose.yml</code>:</p>
|
|
|
|
<pre><code>volumes:
|
|
- cache:/var/www/html/public/cache
|
|
- uploads:/var/www/html/public/uploads
|
|
- data:/var/www/html/data
|
|
- ./App:/var/www/html/App</code></pre>
|
|
|
|
<p>A bind mount at the same path as a <code>COPY</code>'d directory shadows the image layer at container start, so a host-side edit under <code>App/pages/</code> shows up after <code>docker compose restart web</code> — no rebuild, no custom entrypoint logic.</p>
|
|
|
|
<h2>MySQL</h2>
|
|
|
|
<p><code>Lib\Db</code> supports MySQL alongside or instead of SQLite (see <a href="/admin/docs/database">Database</a>). <code>docker-compose.yml</code> has a commented-out <code>db</code> service and <code>mysql-data</code> volume — uncomment both, add a <code>db_connections</code> entry with <code>driver: mysql</code> and matching credentials in <code>App/config.php</code>, and the app container can reach it at hostname <code>db</code>.</p>
|
|
|
|
<h2>Arch-specific notes</h2>
|
|
|
|
<p>Arch's <code>php-apache</code> package is built against <code>mpm_prefork</code>, not <code>httpd</code>'s default <code>mpm_event</code> — the Dockerfile swaps MPMs as part of the build. The Apache/PHP worker user on Arch is <code>http</code>, not Debian's <code>www-data</code>; the Dockerfile <code>chown</code>s the cache/uploads/data/App directories and <code>novaconium/contact-log.txt</code> to <code>http:http</code> at build time so a freshly created named volume (which inherits the image mountpoint's ownership) is writable immediately. If you swap a named volume for a bind mount pointing at a host directory with different ownership, that automatic chown doesn't apply — you may need to adjust permissions on the host side.</p>
|
|
|
|
<p>This is a separate Dockerfile from the one-off Dart Sass build tool described in <a href="/admin/docs/styling">Styling</a> — that one lives at <code>Dockerfile.sass</code>, a Debian-based image whose only job is running the <code>sass</code> CLI, not serving the app.</p>
|
|
{% endblock %}
|