diff --git a/.env.example b/.env.example index c9f51c0..1fba4e9 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,10 @@ # Stack settings. In Portainer, enter these under the stack's "Environment variables". # For the docker compose CLI, copy this file to .env next to compose.yaml. Never commit the completed file. -# Docker network Nginx Proxy Manager is attached to (Portainer > Networks shows the name). -NPM_NETWORK=npm_default +# Host port the app listens on, bound to loopback so only NPMplus (host networking) can reach it. +# Change PROPOSAL_BOT_PORT if 4181 is already taken on the host. +PROPOSAL_BOT_BIND=127.0.0.1 +PROPOSAL_BOT_PORT=4181 # Absolute host folders. The data folder must be writable by UID 1000. PROPOSAL_BOT_DATA_HOST_PATH=/opt/proposal-bot/data diff --git a/README.md b/README.md index 2073e5c..5bf2129 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The image contains only the app code and Chromium (used by the InDesign export). ## Deploy with Portainer -The stack has no published port. Nginx Proxy Manager (NPM) handles HTTPS and reaches the container by name over NPM's Docker network. +NPMplus handles HTTPS. It runs with host networking, so the container publishes its port on the host's loopback address only (`127.0.0.1:4181`). NPMplus can reach that port; other machines cannot. ### 1. Put the project and photo folders on the Docker host @@ -29,7 +29,7 @@ sudo chown -R 1000:1000 /opt/proposal-bot/data # the container runs as UID 10 ### 2. Create the Microsoft Entra app registration 1. Create a web app registration for Proposal Bot with a client secret. -2. Register the callback `https:///auth/microsoft/callback`, using the hostname NPM will serve. +2. Register the callback `https:///auth/microsoft/callback`, using the hostname NPMplus will serve. ### 3. Create the stack @@ -38,16 +38,16 @@ In Portainer, go to **Stacks > Add stack > Repository**: - **Repository URL:** this repo's Gitea URL. Turn on **Authentication** and use a Gitea access token if the repo is private. - **Compose path:** `compose.yaml` - **Environment variables:** add every entry from `.env.example`. **Advanced mode** accepts the whole file pasted in. - - `NPM_NETWORK`: the network NPM's container is attached to. To find it, open NPM's container in Portainer and look at its network section, usually something like `npm_default`. + - `PROPOSAL_BOT_PORT`: leave at `4181` unless that port is already in use on the host. - `PROPOSAL_BOT_DATA_HOST_PATH` and `PROPOSAL_BOT_PROJECT_IMAGES_HOST_PATH`: the folders from step 1. Use absolute paths. A relative path would end up inside Portainer's copy of the repo and be lost on redeploy. - `MICROSOFT_REDIRECT_URI`: exactly the callback from step 2. Deploy the stack. Portainer builds the image on the host, which takes a few minutes the first time because it installs Chromium. The container should show **healthy**. Its logs show startup warnings, such as missing sign-in settings or a `data` folder the container cannot write to. -### 4. Add the NPM proxy host +### 4. Add the NPMplus proxy host - **Domain:** the Proposal Bot hostname -- **Forward:** scheme `http`, hostname `proposal-bot`, port `4181` +- **Forward:** scheme `http`, hostname `127.0.0.1`, port `4181` (or your `PROPOSAL_BOT_PORT`) - **SSL tab:** request or choose a certificate, and turn on **Force SSL** - **Advanced tab:** paste the lines below so long InDesign exports are not cut off after 60 seconds: @@ -68,7 +68,7 @@ Copy `.env.example` to `.env`, fill it in, and run `docker compose up -d --build ## Sign-in -Sign-in uses Microsoft Entra and the email allowlist in `PROPOSAL_BOT_ALLOWED_EMAILS` (comma-separated). Microsoft only accepts HTTPS callbacks, which NPM provides. +Sign-in uses Microsoft Entra and the email allowlist in `PROPOSAL_BOT_ALLOWED_EMAILS` (comma-separated). Microsoft only accepts HTTPS callbacks, which NPMplus provides. Sessions are kept in memory, so restarting or redeploying the container signs everyone out. diff --git a/compose.yaml b/compose.yaml index 62029b9..99b0a59 100644 --- a/compose.yaml +++ b/compose.yaml @@ -9,9 +9,10 @@ services: restart: unless-stopped # Reaps the headless Chromium processes the InDesign export starts. init: true - # No published port: Nginx Proxy Manager reaches http://proposal-bot:4181 over its Docker network. - networks: - - proxy + # Published on the host's loopback only. NPMplus (host networking) forwards to http://127.0.0.1:4181; + # other machines cannot reach the port directly. + ports: + - "${PROPOSAL_BOT_BIND:-127.0.0.1}:${PROPOSAL_BOT_PORT:-4181}:4181" environment: HOST: 0.0.0.0 PORT: 4181 @@ -33,8 +34,3 @@ services: source: ${PROPOSAL_BOT_PROJECT_IMAGES_HOST_PATH:?Set PROPOSAL_BOT_PROJECT_IMAGES_HOST_PATH to an absolute host folder for the photo library} target: /app/Project Images read_only: true - -networks: - proxy: - external: true - name: ${NPM_NETWORK:?Set NPM_NETWORK to the Docker network Nginx Proxy Manager is attached to}