Project

General

Profile

NPM » History » Version 3

Redmine Admin, 10/31/2026 07:01 PM
deploy-publish.sh

1 3 Redmine Admin
*Chapter 1 of the dmz-web documentation · headings are numbered like the cheat sheets · index: [[Wiki]]*
2
3 2 Redmine Admin
Unit: `nginx-proxy-manager.container`. Published on **host 81 → 80, 444 → 443**
4
(rootless can't bind <1024); admin UI on **:8181**, reachable only from the
5
subnets allowed by firewalld rich rules (`firewall-cmd --list-rich-rules`, root):
6
10.202.10.0/24 (VB21 = home LAN, own FortiGate, S2S to HQ), 192.168.100.0/24
7
(MDS-HQ office LAN), 172.16.103.0/24 (the host's own DMZ segment). Deliberately NOT the SSL-VPN pool (10.21.0.0/24): the
8
host rule must not depend on who the FortiGate let onto the VPN; from the road use
9
the SSH tunnel. A new admin subnet = one more rich rule
10
(`--permanent --add-rich-rule='rule family=ipv4 source address=<net>/24 port port=8181 protocol=tcp accept'` + `--reload`).
11
Fallback from anywhere SSH works: `ssh -L 8181:127.0.0.1:8181 root@dmz-web` → `http://localhost:8181`.
12
The FortiGate VIP
13
does the public **443 → 444** translation. No hairpin NAT, so from inside the
14
public names resolve to the WAN IP and don't work — see [[Health Check]].
15 1 Redmine Admin
16 2 Redmine Admin
NPM must be a member of every site's network to reach `site-<name>:80` by
17
container name. Each new site adds three lines to the unit, above the
18
`# --- next site: …` marker comments (`add-wordpress-site.sh` does this
19 1 Redmine Admin
automatically; for Redmine/Snipe-IT do it by hand):
20
21 2 Redmine Admin
```ini
22 1 Redmine Admin
[Unit]
23
After=net-<name>-network.service
24
Requires=net-<name>-network.service
25
[Container]
26
Network=net-<name>.network
27
```
28
29
then `cp` to `~/.config/containers/systemd/`, `daemon-reload`, `restart nginx-proxy-manager.service`.
30
31 2 Redmine Admin
**Before any `cp` of this unit: the repo copy must contain every `Network=` line
32
the live copy has.** On 2026-10-25 `snipeit-install.sh` copied a repo version that
33
only knew `net-snipeit` over the live unit → NPM left the other three networks →
34
every site 502 until the lines were re-added. Check with
35
`diff <(grep '^Network=' ~/.config/containers/systemd/nginx-proxy-manager.container) <(grep '^Network=' ~/deploy/quadlet/nginx-proxy-manager.container)`
36
(empty = safe). Restarting NPM drops every site for ~10–20 s — all three install scripts do it.
37 1 Redmine Admin
38 2 Redmine Admin
Proxy host (UI or API): Domain `<domain>` → scheme http, Forward Hostname
39
`site-<name>`, Forward Port 80 (Redmine: 3000), Block Common Exploits,
40
Websockets; SSL tab → Let's Encrypt, Force SSL, HTTP/2.
41
LE needs DNS A record + FortiGate VIP live first (HTTP-01 challenge comes in
42
over 80 → 81). The LE contact email is the NPM *user account's* email, not a
43 1 Redmine Admin
per-cert setting.
44
45 2 Redmine Admin
API credentials are Podman secrets `npm-admin-identity` / `npm-admin-secret`.
46 1 Redmine Admin
Quick API test:
47
48 2 Redmine Admin
```bash
49 1 Redmine Admin
curl -s http://localhost:8181/api/ | head -c 200
50
podman network inspect net-<name> | jq '.[0].containers | keys'   # must list nginx-proxy-manager
51
```
52
53 2 Redmine Admin
Restrict an internal-only app (Snipe-IT, Redmine admin): NPM **Access List**
54 1 Redmine Admin
with the VPN/office ranges attached to that proxy host.
55
56
---
57 2 Redmine Admin
_Source: `dmz-web-podman-cheatsheet.md` v1.2 in the `dmz-web-deploy` repo ([[Releases]]). Edit the wiki and the repo copy together._