docker to be more inline with other projects and best practices
This commit is contained in:
+76
-4
@@ -1,12 +1,84 @@
|
||||
.git/
|
||||
# .dockerignore — defines the build context used by `COPY . .`.
|
||||
#
|
||||
# Ignoring a path keeps EVERYTHING under it out of the context, which is what
|
||||
# makes "copy the tree instead of listing files" safe: the allowlist that used
|
||||
# to live in eight `COPY ./x /app/x` lines is now simply the absence of a
|
||||
# pattern here. The failure mode is inverted — a missed entry fails the build
|
||||
# loudly ("not found in build context") instead of silently baking a file in.
|
||||
#
|
||||
# Rules that matter (Guiding Light §6.3): `config/`, `bin/`, `public/` and the
|
||||
# composer manifests are never ignored, and /Caddyfile is the inverse case —
|
||||
# it is ignored, because the final stage copies it from `docker/Caddyfile`.
|
||||
|
||||
# ── VCS & CI ────────────────────────────────────────────────────────────────
|
||||
.git
|
||||
.gitignore
|
||||
.editorconfig
|
||||
.gitea
|
||||
.ci
|
||||
|
||||
# ── Secrets: never bake these into a layer (§6.1, §8.12) ────────────────────
|
||||
# Bare `.env` included deliberately: it is exactly the file a developer has
|
||||
# locally and must not land in an image layer.
|
||||
.env
|
||||
.env.local
|
||||
.env.local.php
|
||||
.env.*.local
|
||||
.env.dev
|
||||
.env.test
|
||||
host.env
|
||||
config/secrets/prod/prod.decrypt.private.php
|
||||
|
||||
# ── Local runtime state (§5.2) ──────────────────────────────────────────────
|
||||
# var/ holds the dev cache and logs; the prod cache is warmed inside the image.
|
||||
var/
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
*.db
|
||||
|
||||
# ── Rebuilt inside the image from composer.lock ─────────────────────────────
|
||||
vendor/
|
||||
|
||||
# ── Dev / test artefacts not needed at runtime ──────────────────────────────
|
||||
tests/
|
||||
.phpunit.cache/
|
||||
.phpunit.result.cache
|
||||
phpunit.xml
|
||||
phpunit.dist.xml
|
||||
.php-cs-fixer.cache
|
||||
.php-cs-fixer.dist.php
|
||||
.php-cs-fixer.php
|
||||
phpstan.neon.dist
|
||||
phpstan-baseline.neon
|
||||
|
||||
# ── Build inputs that aren't payload ────────────────────────────────────────
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
docker-bake.hcl
|
||||
compose*.yaml
|
||||
docker-compose*.yaml
|
||||
|
||||
# ── Docs, examples and host-side tooling ────────────────────────────────────
|
||||
# The root Caddyfile is the host-side example (docs/examples/ has a longer
|
||||
# one); the image's config is docker/Caddyfile, copied explicitly below.
|
||||
docs/
|
||||
*.md
|
||||
.env
|
||||
.env.test
|
||||
.env.local
|
||||
license.txt
|
||||
Caddyfile
|
||||
Domainfile
|
||||
run.sh
|
||||
deploy.sh
|
||||
bin/composer
|
||||
bin/dev.sh
|
||||
bin/franken.sh
|
||||
bin/phpunit
|
||||
composer.phar
|
||||
|
||||
# ── Generated config reference (regenerate with config:dump) ────────────────
|
||||
config/reference.php
|
||||
|
||||
# ── Editor / OS noise ───────────────────────────────────────────────────────
|
||||
.idea
|
||||
.vscode
|
||||
*.swp
|
||||
.DS_Store
|
||||
|
||||
@@ -66,6 +66,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
deliberately excluded: they are consumed by the proxy's `forward_auth`
|
||||
check and never reach the browser.
|
||||
|
||||
### Changed
|
||||
- **Dockerfile rebuild — same layout as the rest of the portfolio** (Guiding
|
||||
Light §6.4). The build now copies the tree (`COPY . .`) and lets
|
||||
`.dockerignore` decide what reaches the context, instead of maintaining a
|
||||
hand-written `COPY ./x /app/x` allowlist that had to be kept in step with
|
||||
the project layout. `var/` — which the old file list never copied — now
|
||||
simply stays out via the ignore file.
|
||||
- **The image runs as a non-root `app` user** (uid/gid 1000, the same
|
||||
convention as task-loom/context-shuttle). `/data` (cache pools) and
|
||||
`/config` are created and owned by it. This resolves the last failing
|
||||
conformance check (§6.4 `dockerfile-nonroot`).
|
||||
- **`.dockerignore` rebuilt on the Guiding Light §6.2 baseline** — in
|
||||
particular `.env` is now excluded explicitly (§6.1), so a developer's
|
||||
local environment file can never be baked into a layer.
|
||||
- **`docker/php.ini` and `docker/Caddyfile` added.** The PHP overrides
|
||||
(`expose_php=Off`, error/log settings, OPcache timestamps off, APCu for
|
||||
CLI) and the FrankenPHP app config now live in the repository instead of
|
||||
being three heredocs inside the Dockerfile, so what the image runs is
|
||||
reviewable in a diff.
|
||||
- **Runtime base image pinned to `dunglas/frankenphp:1-php8.5-trixie` and
|
||||
APCu installed via the base image's `install-php-extensions`** — the
|
||||
versioned tag replaces the floating one, and the build no longer drags a
|
||||
compiler toolchain into the runtime layer to build one extension.
|
||||
- **`/app` is now the whole project.** The old image only shipped
|
||||
`bin/console`, `config`, `public`, `src`, `templates` and the composer
|
||||
manifests; `config/reference.php` and other loose files are now present.
|
||||
No application path changes: `public/index.php` and `bin/console` resolve
|
||||
through the same relative paths.
|
||||
- `bin/franken.sh` mounts the share dir at its new default
|
||||
(`/app/var/share`) instead of the old `/app/var/share` bind that no longer
|
||||
matched the image.
|
||||
|
||||
### Fixed
|
||||
- **`composer dump-env prod --empty` removed.** preauth does not depend on
|
||||
`symfony/dotenv` (it is not in `composer.lock`), so nothing reads a `.env`
|
||||
file in the container — the command only produced a dead
|
||||
`.env.local.php` in the build stage. The Dockerfile comment that claimed
|
||||
otherwise is gone with it.
|
||||
- **`composer install` no longer ships a classmap missing `App\`.** The old
|
||||
build ran `install --optimize-autoloader` before `src/` was copied, and the
|
||||
final `--classmap-authoritative` dump happened before any `COPY . .`; the
|
||||
classmap is now rebuilt after the application is in place.
|
||||
- **The HEALTHCHECK can actually pass.** It probed `curl -f http://localhost/`,
|
||||
and preauth answers every unauthenticated request to `/` with the login page
|
||||
and a `401` — so the probe failed 100% of the time and the container was
|
||||
permanently marked unhealthy. It now probes Caddy's loopback admin endpoint
|
||||
(the base image's own default probe, restated explicitly), which is why the
|
||||
Caddyfile deliberately does not disable the admin API.
|
||||
- **`expose_php` is now genuinely off in the runtime image.** The base image
|
||||
ships the `php.ini-production` *template* but no active `php.ini`, so the
|
||||
previous `cp` of the template was the only thing setting it — and the
|
||||
`docker/php.ini` overrides are loaded after it, so stating it here makes the
|
||||
intent explicit; verified against a real boot that no `X-Powered-By` header
|
||||
is emitted.
|
||||
- `bin/franken.sh` no longer passes `DEFAULT_URI`, which the application does
|
||||
not read (`config/packages/routing.yaml` sets the router's `default_uri`).
|
||||
|
||||
## [1.0.0] — v1.0 Release
|
||||
|
||||
### Security
|
||||
|
||||
+109
-65
@@ -1,84 +1,128 @@
|
||||
# use build image, to simplify final image
|
||||
# syntax=docker/dockerfile:1.7
|
||||
#
|
||||
# PreAuth — one app, one image.
|
||||
#
|
||||
# Multi-stage FrankenPHP build: dependencies in a builder, the runtime image
|
||||
# only gets the finished tree. Runtime: FrankenPHP worker mode, non-root,
|
||||
# state on /data. TLS is terminated upstream of the container; FrankenPHP
|
||||
# serves :80.
|
||||
#
|
||||
# Build context: the whole tree (`COPY . .`), narrowed by .dockerignore. The
|
||||
# allowlist that used to live in the eight `COPY ./x /app/x` below is in that
|
||||
# file now — a directory that must ship is a directory it does not exclude.
|
||||
#
|
||||
# Secrets are injected at runtime as env vars, never baked in (§8.12).
|
||||
|
||||
# ── Stage: build — composer dependencies + prod app ────────────────────────
|
||||
FROM php:8.5-trixie AS build
|
||||
|
||||
# install APCu and composer
|
||||
RUN pecl install apcu && \
|
||||
docker-php-ext-enable apcu
|
||||
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
||||
RUN apt-get update && \
|
||||
apt-get install -y unzip git
|
||||
# Build-time set: git (composer resolves packages over VCS) and unzip (dist
|
||||
# extraction). Neither reaches the runtime image.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends git unzip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# symfony required environment variables
|
||||
ENV APP_DEBUG=0
|
||||
ENV APP_ENV=prod
|
||||
ENV APP_SHARE_DIR=/data/preauth
|
||||
# APCu and Composer, both only needed to compile the application.
|
||||
RUN pecl install apcu \
|
||||
&& docker-php-ext-enable apcu \
|
||||
&& docker-php-ext-enable opcache
|
||||
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||
|
||||
# load application into build image
|
||||
RUN mkdir -p /data/preauth
|
||||
RUN mkdir -p /app/bin
|
||||
WORKDIR /app
|
||||
COPY ./bin/console /app/bin/console
|
||||
COPY ./config /app/config
|
||||
COPY ./public /app/public
|
||||
COPY ./src /app/src
|
||||
COPY ./templates /app/templates
|
||||
COPY ./composer.json /app/composer.json
|
||||
COPY ./composer.lock /app/composer.lock
|
||||
COPY ./symfony.lock /app/symfony.lock
|
||||
|
||||
# install application dependencies
|
||||
RUN composer install --no-dev --optimize-autoloader
|
||||
RUN composer dump-env prod --empty
|
||||
# Manifests first so the dependency layer only rebuilds when they change.
|
||||
COPY composer.json composer.lock symfony.lock ./
|
||||
RUN composer install --no-dev --no-interaction --prefer-dist \
|
||||
--optimize-autoloader --no-scripts
|
||||
|
||||
# start creating final image
|
||||
# Named `app` so docker-bake.hcl can target it explicitly. Naming the final
|
||||
# stage changes nothing for a plain `docker build` — the last stage is still
|
||||
# the default build target.
|
||||
FROM dunglas/frankenphp:php8.5-trixie AS app
|
||||
# Copy the application. .dockerignore keeps vendor/, var/, tests/ and the
|
||||
# local env files out of the context; composer install has already run, so
|
||||
# its vendor/ wins.
|
||||
COPY . .
|
||||
|
||||
# install APCu and curl (needed for healthcheck)
|
||||
RUN pecl install apcu && \
|
||||
docker-php-ext-enable apcu
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends curl && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
# src/ was not in the context when composer install ran, so the authoritative
|
||||
# classmap has to be rebuilt now that the application code is present.
|
||||
#
|
||||
# There is deliberately no `composer dump-env` step: preauth does not depend
|
||||
# on symfony/dotenv (it is absent from composer.lock), so nothing reads a
|
||||
# .env file at runtime and the dump would only add a dead file. Runtime
|
||||
# configuration comes from the environment, with the defaults documented in
|
||||
# config/services.yaml.
|
||||
RUN composer dump-autoload --classmap-authoritative --no-dev
|
||||
|
||||
# symfony required environment variables
|
||||
ENV APP_DEBUG=0
|
||||
ENV APP_ENV=prod
|
||||
ENV APP_SHARE_DIR=/data/preauth
|
||||
# Build-time smoke of the autoloader + config compile. No APP_SECRET is
|
||||
# needed: %env(APP_SECRET)% is not resolved at compile time, and the cache is
|
||||
# cleared afterwards anyway — the real warm-up runs at container start with
|
||||
# the injected secrets (entrypoint; §8.12).
|
||||
#
|
||||
# The cache is written to the share dir, not var/cache: the runtime image
|
||||
# ships without a warmed var/cache, so the first container start does the
|
||||
# build for its own APP_SECRET (and the pages/ filesystem pool needs a
|
||||
# writable dir owned by the app user).
|
||||
RUN APP_ENV=prod APP_SHARE_DIR=/data/preauth bin/console cache:warmup \
|
||||
&& rm -rf var/cache/* var/log/*
|
||||
|
||||
# worker thread lifecycle: restart each PHP thread after N requests to
|
||||
# contain slow memory growth. Matches the previous default loop count of
|
||||
# runtime/frankenphp-symfony (removed in the Symfony 8.1 upgrade).
|
||||
# Expose as a build arg so images can bake in a different default;
|
||||
# MAX_REQUESTS=0 disables restarts. Runtime override: the same env var is
|
||||
# read by the Caddyfile placeholder.
|
||||
ARG MAX_REQUESTS=500
|
||||
ENV MAX_REQUESTS=$MAX_REQUESTS
|
||||
# ── Stage: app — the runtime image ─────────────────────────────────────────
|
||||
FROM dunglas/frankenphp:1-php8.5-trixie AS app
|
||||
|
||||
# Runtime set: curl is the HEALTHCHECK's probe; APCu is the state store.
|
||||
# The base image ships the install-php-extensions script, which builds the
|
||||
# extension and removes its own build dependencies afterwards — so git,
|
||||
# autoconf and gcc never reach this stage the way `pecl install` needed them.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends curl \
|
||||
&& install-php-extensions apcu \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# PHP configuration. The packaged production baseline is copied in first
|
||||
# (the base image ships the template, not an active php.ini), then the app's
|
||||
# own overrides are layered on top of it — they restate the security-critical
|
||||
# switches so the intent survives a base-image default changing underneath us.
|
||||
COPY docker/php.ini $PHP_INI_DIR/conf.d/zz-preauth.ini
|
||||
RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
|
||||
COPY docker/Caddyfile /etc/frankenphp/Caddyfile
|
||||
COPY docker/entrypoint.sh /usr/local/bin/entrypoint
|
||||
RUN chmod +x /usr/local/bin/entrypoint
|
||||
|
||||
# load application into final image
|
||||
WORKDIR /app
|
||||
COPY --from=build /data/preauth /data/preauth
|
||||
COPY --from=build /app /app
|
||||
|
||||
# configure container
|
||||
COPY ./Caddyfile /etc/frankenphp/Caddyfile
|
||||
RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
|
||||
RUN echo 'expose_php = off' > $PHP_INI_DIR/conf.d/restrict.ini
|
||||
# console needs apc to manage cache
|
||||
RUN echo 'apc.enable_cli = on' > $PHP_INI_DIR/conf.d/console.ini
|
||||
# Non-root runtime user (Guiding Light §6.4). uid/gid 1000, same convention
|
||||
# as task-loom/task-weaver/context-shuttle. /data holds the cache pools the
|
||||
# app writes at runtime, /config is Caddy's own XDG dir.
|
||||
RUN groupadd --system --gid 1000 app \
|
||||
&& useradd --system --uid 1000 --gid app \
|
||||
--home-dir /app --shell /usr/sbin/nologin app \
|
||||
&& mkdir -p /data/preauth /config \
|
||||
&& chown -R app:app /app /data
|
||||
|
||||
# app uses var folder for cache storage
|
||||
USER app
|
||||
|
||||
# FrankenPHP listens on :80; TLS is terminated by the external proxy.
|
||||
# APP_SHARE_DIR points the filesystem cache pools (sessions, rate limiter)
|
||||
# at the volume. MAX_REQUESTS is a build arg so images can bake in a
|
||||
# different worker-recycle default; the Caddyfile placeholder reads it.
|
||||
ARG MAX_REQUESTS=500
|
||||
ENV APP_ENV=prod \
|
||||
APP_DEBUG=0 \
|
||||
APP_SHARE_DIR=/data/preauth \
|
||||
SERVER_NAME=:80 \
|
||||
MAX_REQUESTS=$MAX_REQUESTS
|
||||
|
||||
# Persistent state: cache pools (sessions, backup codes, rate limits) and
|
||||
# Caddy's data. Only /data is needed at runtime; /config is declared because
|
||||
# the base image points XDG_CONFIG_HOME at it.
|
||||
VOLUME ["/config", "/data"]
|
||||
|
||||
# runs http on standard port
|
||||
EXPOSE 80
|
||||
|
||||
# healthcheck
|
||||
HEALTHCHECK --interval=5m \
|
||||
--retries=3 \
|
||||
--start-interval=1s \
|
||||
--start-period=10s \
|
||||
--timeout=2s \
|
||||
CMD curl http://localhost || exit 1
|
||||
# Liveness: Caddy's own admin endpoint, bound to loopback inside the
|
||||
# container, exactly as the base image declares it (restated here so the
|
||||
# probe does not depend on the upstream default staying put). The app's own
|
||||
# routes cannot serve this: an unauthenticated request gets the login page
|
||||
# with a 401, so `curl -f` against HTTP would always report unhealthy.
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
||||
CMD curl -f http://localhost:2019/metrics || exit 1
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/entrypoint"]
|
||||
CMD ["frankenphp", "run", "--config", "/etc/frankenphp/Caddyfile"]
|
||||
|
||||
+7
-5
@@ -62,8 +62,10 @@ services preauth protects.
|
||||
|
||||
## Deployment note
|
||||
|
||||
preauth runs as a container and, once
|
||||
[GUIDING-LIGHT §6.4](https://code.devgnome.com/private/ci) is adopted here, will
|
||||
drop privileges via `USER`. The image declares `VOLUME ["/config", "/data"]`;
|
||||
if you pin a `user:` in your compose file, that user must be able to write both
|
||||
paths — otherwise login state and backup codes cannot be persisted.
|
||||
preauth runs as a container and drops privileges via `USER` (Guiding Light
|
||||
§6.4): the image runs as the non-root `app` user (uid/gid 1000) and owns the
|
||||
state paths it needs. Only `/data` is written at runtime — the cache pools
|
||||
behind sessions, backup codes and rate limiting — and `/config` is declared
|
||||
because the base image points Caddy's XDG config dir there. If you pin a
|
||||
different `user:` in your compose file, that user must be able to write to
|
||||
both paths — otherwise login state and backup codes cannot be persisted.
|
||||
|
||||
+1
-3
@@ -9,8 +9,6 @@ docker run --name preauth \
|
||||
-e APP_ENV=dev \
|
||||
-e APP_DEBUG=true \
|
||||
-e APP_SECRET="${APP_SECRET:-$(openssl rand -hex 16)}" \
|
||||
-e APP_SHARE_DIR=var/share \
|
||||
-e DEFAULT_URI=http://localhost \
|
||||
-v ./var/share:/app/var/share \
|
||||
-e APP_SHARE_DIR=/app/var/share \
|
||||
-p 8000:80 \
|
||||
digitaladapt/preauth:dev
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# PreAuth — Caddyfile / FrankenPHP app config.
|
||||
#
|
||||
# The container serves plain HTTP on :80; TLS is terminated by the upstream
|
||||
# proxy. SERVER_NAME=:80 is set in the Dockerfile.
|
||||
#
|
||||
# This is the config the image ships (/etc/frankenphp/Caddyfile). The
|
||||
# Caddyfile in the repository root is the example for host-side setups.
|
||||
{
|
||||
frankenphp {
|
||||
# Restart each PHP worker thread after this many requests, containing
|
||||
# slow memory growth across long uptime. Preserves the 7.4-era default
|
||||
# loop count of runtime/frankenphp-symfony (500) after the Symfony 8.1
|
||||
# upgrade. Set MAX_REQUESTS=0 to disable restarts. The Dockerfile bakes
|
||||
# in the default of 500 via build arg; override at runtime with:
|
||||
# docker run -e MAX_REQUESTS=5000 ...
|
||||
# For full control, the stock FRANKENPHP_CONFIG env var can inject any
|
||||
# directive under this block instead.
|
||||
max_requests {$MAX_REQUESTS}
|
||||
}
|
||||
|
||||
# The admin API is deliberately left at its default: bound to 127.0.0.1
|
||||
# inside the container, where it is the target of the image's
|
||||
# HEALTHCHECK. It is not reachable from outside the container. Do NOT set
|
||||
# `admin off` here without also changing that probe — the app has no 2xx
|
||||
# liveness route to fall back on, because every anonymous request is
|
||||
# answered with the login page and a 401.
|
||||
}
|
||||
|
||||
http:// {
|
||||
root public/
|
||||
rewrite index.php
|
||||
php {
|
||||
root /app/public
|
||||
worker index.php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# PreAuth container entrypoint.
|
||||
#
|
||||
# Responsibilities:
|
||||
# 1. Warm the prod cache with the injected secrets.
|
||||
# 2. Hand off to CMD (FrankenPHP server, or a console override:
|
||||
# `docker exec -it preauth bin/console app:generate-backup-codes`).
|
||||
#
|
||||
# Secrets are env vars injected at runtime, never baked into images (§8.12).
|
||||
# The container has no shell to hand out otherwise — it runs as an unprivileged
|
||||
# user with a nologin shell — so the real boot validation is
|
||||
# `cache:warmup` failing here, which is also what makes it worth doing.
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$APP_ENV" = "prod" ]; then
|
||||
echo "Warming cache..."
|
||||
php bin/console cache:warmup
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
@@ -0,0 +1,41 @@
|
||||
; PreAuth php.ini overrides — merged on top of the FrankenPHP base image
|
||||
; defaults.
|
||||
;
|
||||
; The base image ships no php.ini (only the php.ini-production template), so
|
||||
; the production switches that matter are stated explicitly here rather than
|
||||
; inherited — verified against a real boot: without them the response carries
|
||||
; `X-Powered-By: PHP/8.5.10` and errors would render into the body.
|
||||
;
|
||||
; PreAuth keeps its session state in APCu plus a filesystem cache pool, so the
|
||||
; settings that matter most are the cache ones.
|
||||
|
||||
; Never advertise the interpreter, never print errors to the client. This is
|
||||
; an authentication gateway: a stack trace in a 500 body is an information
|
||||
; leak. Errors go to stderr for the log collector.
|
||||
expose_php = Off
|
||||
display_errors = Off
|
||||
log_errors = On
|
||||
error_log = /proc/self/fd/2
|
||||
|
||||
memory_limit = 256M
|
||||
upload_max_filesize = 2M
|
||||
post_max_size = 8M
|
||||
|
||||
; OPcache for the FrankenPHP worker: the image is immutable, so timestamps
|
||||
; never need revalidating. The CLI console also runs the app, hence
|
||||
; enable_cli = 1.
|
||||
opcache.enable = 1
|
||||
opcache.enable_cli = 1
|
||||
opcache.validate_timestamps = 0
|
||||
opcache.memory_consumption = 128
|
||||
opcache.interned_strings_buffer = 16
|
||||
opcache.max_accelerated_files = 20000
|
||||
|
||||
; APCu — nonce cache, rate limiter and session cache all live in it, and the
|
||||
; console needs it too (`bin/console` commands manage cache state).
|
||||
apc.enabled = 1
|
||||
apc.enable_cli = 1
|
||||
apc.shm_size = 64M
|
||||
apc.ttl = 0
|
||||
|
||||
date.timezone = UTC
|
||||
@@ -1,7 +1,8 @@
|
||||
services:
|
||||
preauth:
|
||||
env_file:
|
||||
# copy ".env.example" to ".env", edit as needed
|
||||
# copy ".env.example" to ".env", edit as needed, and put APP_SECRET
|
||||
# in it (any long random string).
|
||||
# strongly recommend setting TOTP_URI, if not provided the app
|
||||
# will generate one for you, please copy it into your .env file
|
||||
- .env
|
||||
@@ -9,8 +10,10 @@ services:
|
||||
- 80
|
||||
image: digitaladapt/preauth:latest
|
||||
restart: unless-stopped
|
||||
# if you wish to set the user, you must make sure that the user
|
||||
# can write to /config and /data within the container
|
||||
# The image runs as the non-root `app` user (uid/gid 1000) and creates
|
||||
# its state directories owned by that user, so a named volume inherits
|
||||
# the right ownership on first start — no `user:` override is needed.
|
||||
# If you pin one anyway, it must be able to write /config and /data.
|
||||
#user: <uid>:<gid>
|
||||
volumes:
|
||||
- preauth-config:/config
|
||||
@@ -19,4 +22,3 @@ services:
|
||||
volumes:
|
||||
preauth-config:
|
||||
preauth-data:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user