Explorar el Código

Build: make published host port configurable via HTTP_PORT (default 8080)

docker-compose.yml's host port was hard-coded to 8088, forcing operators
to edit the file (and remember to keep it out of merges) to publish on a
different port. Replaced with `${HTTP_PORT:-8080}:80` so the host port
is set in .env alongside APP_BASE_URL. Default moves from 8088 → 8080
so the compose default and APP_BASE_URL default finally agree.

Docs: SPEC §8 env block, README quick-setup, admin-manual §3.2 (no more
mismatch caveat) + new §3.3 "Host port" + §4.1 / §4.4 / §4.5 updates;
old §3.3-§3.7 renumbered to §3.4-§3.8 with two cross-refs fixed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ClaudePriv@chiappa.zhdk.ch hace 4 horas
padre
commit
4354266825
Se han modificado 5 ficheros con 46 adiciones y 24 borrados
  1. 5 0
      .env.example
  2. 3 2
      README.md
  3. 2 1
      SPEC.md
  4. 32 20
      doc/admin-manual.md
  5. 4 1
      docker-compose.yml

+ 5 - 0
.env.example

@@ -17,6 +17,11 @@ OIDC_ENABLED=true
 # Used to build the OIDC redirect URI {APP_BASE_URL}/auth/callback
 # Used to build the OIDC redirect URI {APP_BASE_URL}/auth/callback
 APP_BASE_URL=http://localhost:8080
 APP_BASE_URL=http://localhost:8080
 
 
+# Host port the docker-compose stack publishes (container side is fixed at
+# Apache:80). Pick any free port on the host. Keep APP_BASE_URL in sync —
+# the OIDC redirect URI registered in Entra must match exactly.
+HTTP_PORT=8080
+
 # Path to the SQLite database file inside the container. Leave as-is unless
 # Path to the SQLite database file inside the container. Leave as-is unless
 # you have a specific reason to change it. The parent dir is the mounted
 # you have a specific reason to change it. The parent dir is the mounted
 # volume (/var/www/data).
 # volume (/var/www/data).

+ 3 - 2
README.md

@@ -51,12 +51,13 @@ cp .env.example .env
 #    ENTRA_CLIENT_SECRET instead (or in addition).
 #    ENTRA_CLIENT_SECRET instead (or in addition).
 chmod 600 .env
 chmod 600 .env
 
 
-# 4. Build and start the container (compose maps host port 8088 → container 80)
+# 4. Build and start the container (compose maps host port HTTP_PORT
+#    from .env → container 80; default 8080, change in .env to taste)
 docker compose up -d --build
 docker compose up -d --build
 #    Equivalent shortcut once `make` is installed: `make prod`
 #    Equivalent shortcut once `make` is installed: `make prod`
 
 
 # 5. Open the app
 # 5. Open the app
-xdg-open http://localhost:8088   # or just visit it in a browser
+xdg-open http://localhost:8080   # substitute your HTTP_PORT if changed
 ```
 ```
 
 
 If you signed in via the local-admin fallback you are immediately the
 If you signed in via the local-admin fallback you are immediately the

+ 2 - 1
SPEC.md

@@ -326,6 +326,7 @@ ENTRA_TENANT_ID=
 ENTRA_CLIENT_ID=
 ENTRA_CLIENT_ID=
 ENTRA_CLIENT_SECRET=
 ENTRA_CLIENT_SECRET=
 APP_BASE_URL=http://localhost:8080
 APP_BASE_URL=http://localhost:8080
+HTTP_PORT=8080              # host port docker-compose publishes (→ container :80)
 DB_PATH=/var/www/data/app.sqlite
 DB_PATH=/var/www/data/app.sqlite
 SESSION_PATH=/var/www/data/sessions
 SESSION_PATH=/var/www/data/sessions
 APP_ENV=production
 APP_ENV=production
@@ -1710,7 +1711,7 @@ cp .env.example .env
 # Fill Entra vars, OR set LOCAL_ADMIN_EMAIL + LOCAL_ADMIN_PASSWORD_HASH
 # Fill Entra vars, OR set LOCAL_ADMIN_EMAIL + LOCAL_ADMIN_PASSWORD_HASH
 # (see README's Quick setup for the password_hash() one-liner)
 # (see README's Quick setup for the password_hash() one-liner)
 make prod   # or `docker compose up --build`
 make prod   # or `docker compose up --build`
-# open http://localhost:8088
+# open http://localhost:8080
 ```
 ```
 
 
 The SQLite file lives at `./data/app.sqlite` on the host; nuking it resets
 The SQLite file lives at `./data/app.sqlite` on the host; nuking it resets

+ 32 - 20
doc/admin-manual.md

@@ -83,11 +83,22 @@ APP_BASE_URL=https://sprint.example.com
 The base URL the application is reachable at, **without** trailing slash.
 The base URL the application is reachable at, **without** trailing slash.
 This is used to construct the OIDC redirect URI and must match exactly
 This is used to construct the OIDC redirect URI and must match exactly
 what is registered in Entra. For local testing the default
 what is registered in Entra. For local testing the default
-`http://localhost:8080` is fine — but the compose file ships the app on
-port `8088`, so use `http://localhost:8088` if you have not edited
-`docker-compose.yml`.
+`http://localhost:8080` matches the default `HTTP_PORT` (see §3.3), so
+no edits are needed unless you have changed one or the other.
 
 
-### 3.3 Database and session storage paths
+### 3.3 Host port
+
+```
+HTTP_PORT=8080
+```
+
+The host port `docker-compose.yml` publishes for the app (container side
+is fixed at Apache port 80). Default `8080`. Pick any free host port; you
+do not need to edit `docker-compose.yml`. Whatever you set here must
+match the port in `APP_BASE_URL` and the redirect URI registered in
+Entra.
+
+### 3.4 Database and session storage paths
 
 
 ```
 ```
 DB_PATH=/var/www/data/app.sqlite
 DB_PATH=/var/www/data/app.sqlite
@@ -98,7 +109,7 @@ Leave the defaults unless you are also remapping the volume. The parent
 directory `/var/www/data` is the volume mount point inside the container
 directory `/var/www/data` is the volume mount point inside the container
 and corresponds to `./data/` on the host.
 and corresponds to `./data/` on the host.
 
 
-### 3.4 Environment mode
+### 3.5 Environment mode
 
 
 ```
 ```
 APP_ENV=production
 APP_ENV=production
@@ -107,7 +118,7 @@ APP_ENV=production
 `production` silences verbose PHP errors. Any other value (e.g. `dev`)
 `production` silences verbose PHP errors. Any other value (e.g. `dev`)
 turns them on — useful when troubleshooting in a non-public install.
 turns them on — useful when troubleshooting in a non-public install.
 
 
-### 3.5 Reverse proxy and HTTPS
+### 3.6 Reverse proxy and HTTPS
 
 
 ```
 ```
 TRUSTED_PROXIES=10.0.0.0/8,192.168.0.0/16
 TRUSTED_PROXIES=10.0.0.0/8,192.168.0.0/16
@@ -164,7 +175,7 @@ location / {
 }
 }
 ```
 ```
 
 
-### 3.6 Nominating the first administrator (OIDC)
+### 3.7 Nominating the first administrator (OIDC)
 
 
 Historically the first user to complete sign-in via *any* path was promoted
 Historically the first user to complete sign-in via *any* path was promoted
 to administrator. On a public-facing first deploy that is a land-grab risk
 to administrator. On a public-facing first deploy that is a land-grab risk
@@ -190,7 +201,7 @@ Either / both / neither may be set:
 - **Both set**: the signing user is promoted on a match against either field.
 - **Both set**: the signing user is promoted on a match against either field.
 - **One set**: only that channel matters.
 - **One set**: only that channel matters.
 - **Neither set**: the OIDC path will *never* auto-promote. In that case
 - **Neither set**: the OIDC path will *never* auto-promote. In that case
-  bootstrap the first administrator via the local-admin fallback (§3.7) or
+  bootstrap the first administrator via the local-admin fallback (§3.8) or
   by setting `users.is_admin = 1` directly in `app.sqlite`.
   by setting `users.is_admin = 1` directly in `app.sqlite`.
 
 
 Auto-promotion additionally requires that no administrator already exists
 Auto-promotion additionally requires that no administrator already exists
@@ -198,11 +209,11 @@ Auto-promotion additionally requires that no administrator already exists
 promotions go through the **Users** page (§5.1). The promotion is recorded
 promotions go through the **Users** page (§5.1). The promotion is recorded
 in the audit log as `BOOTSTRAP_ADMIN` with `via=oidc`.
 in the audit log as `BOOTSTRAP_ADMIN` with `via=oidc`.
 
 
-The local-admin fallback (§3.7) is itself an explicit env-bootstrap and
+The local-admin fallback (§3.8) is itself an explicit env-bootstrap and
 does not require the variables above — its `BOOTSTRAP_ADMIN` audit row is
 does not require the variables above — its `BOOTSTRAP_ADMIN` audit row is
 tagged `via=local`.
 tagged `via=local`.
 
 
-### 3.7 Local admin fallback (optional)
+### 3.8 Local admin fallback (optional)
 
 
 ```
 ```
 LOCAL_ADMIN_EMAIL=admin@example.com
 LOCAL_ADMIN_EMAIL=admin@example.com
@@ -293,8 +304,8 @@ What happens:
    apply every file in `migrations/` BEFORE Apache binds the port. If
    apply every file in `migrations/` BEFORE Apache binds the port. If
    a migration fails, the container exits non-zero and Apache never
    a migration fails, the container exits non-zero and Apache never
    starts — check `docker compose logs` for the migration's stderr.
    starts — check `docker compose logs` for the migration's stderr.
-3. Apache then starts on port 80, exposed on the host as port
-   **8088** (see `docker-compose.yml`).
+3. Apache then starts on port 80, exposed on the host as the port set
+   by `HTTP_PORT` in `.env` (default **8080** — see §3.3 / §4.5).
 
 
 The web request path itself never applies SQL — it only checks that
 The web request path itself never applies SQL — it only checks that
 `schema_version` matches the on-disk migration set and refuses to serve
 `schema_version` matches the on-disk migration set and refuses to serve
@@ -302,7 +313,7 @@ The web request path itself never applies SQL — it only checks that
 A forgotten deploy step therefore produces a loud, fast-failing 503
 A forgotten deploy step therefore produces a loud, fast-failing 503
 instead of silent stale-schema serving (R01-N22).
 instead of silent stale-schema serving (R01-N22).
 
 
-Open `http://<host>:8088`. If you used the local-admin fallback, sign
+Open `http://<host>:8080`. If you used the local-admin fallback, sign
 in at `/auth/local`. Otherwise click the Entra sign-in CTA on `/`.
 in at `/auth/local`. Otherwise click the Entra sign-in CTA on `/`.
 
 
 ### 4.2 Running detached (recommended for production)
 ### 4.2 Running detached (recommended for production)
@@ -353,20 +364,21 @@ returns `200 OK` with a small JSON body. Use it from a load balancer or
 uptime monitor:
 uptime monitor:
 
 
 ```bash
 ```bash
-curl -fsS http://<host>:8088/healthz
+curl -fsS http://<host>:8080/healthz
 ```
 ```
 
 
 ### 4.5 Changing the host port
 ### 4.5 Changing the host port
 
 
-Edit the `ports` line in `docker-compose.yml`:
+Set `HTTP_PORT` in `.env` to any free port on the host:
 
 
-```yaml
-ports:
-  - "8088:80"
+```
+HTTP_PORT=9090
 ```
 ```
 
 
-Change `8088` to any free port on the host. After editing, `docker
-compose up -d` is enough — no rebuild required. Update `APP_BASE_URL`
+`docker-compose.yml` substitutes the variable into the `ports` mapping
+(`"${HTTP_PORT:-8080}:80"`); the default `8080` applies when the
+variable is unset. After editing, `docker compose up -d` re-creates the
+container with the new port — no rebuild required. Update `APP_BASE_URL`
 in `.env` and the redirect URI in Entra to match.
 in `.env` and the redirect URI in Entra to match.
 
 
 ---
 ---

+ 4 - 1
docker-compose.yml

@@ -4,7 +4,10 @@ services:
       context: .
       context: .
       target: runtime
       target: runtime
     ports:
     ports:
-      - "8088:80"
+      # Host port comes from .env (HTTP_PORT). Default 8080 matches the
+      # APP_BASE_URL default in .env.example. Container side is fixed at
+      # 80 (Apache). Keep APP_BASE_URL in sync if you change it.
+      - "${HTTP_PORT:-8080}:80"
     env_file: .env
     env_file: .env
     volumes:
     volumes:
       - ./data:/var/www/data
       - ./data:/var/www/data