feat(service-ports): remove hardcoded ports from docker-compose, make all service ports configurable

All host port bindings in docker-compose.yml now use \${VAR:-default} substitution,
driven by the .env file generated by ip_utils.write_env_file(). Changing a port in
Settings triggers a per-container pending-restart banner so only the affected container
is restarted on Apply.

- ip_utils: add PORT_DEFAULTS, PORT_ENV_VAR_NAMES, PORT_TO_CONTAINERS; extend
  write_env_file() to accept optional ports dict and write all port env vars
- docker-compose: convert all hardcoded port bindings to \${VAR:-default} form
- app.py: add _collect_service_ports helper; detect port changes in update_config,
  write updated .env and call _set_pending_restart with specific container list;
  update _set_pending_restart to merge/accumulate pending state with containers list;
  update apply_pending_config to use --no-deps <service> for targeted restarts
- config_manager: add submission_port, webmail_port to email schema; add manager_port
  to files schema
- Settings.jsx: make all email/files ports editable, add submission_port, webmail_port,
  manager_port fields; update stale identity note
- tests: 8 new tests for PORT_DEFAULTS, PORT_ENV_VAR_NAMES, and port override in write_env_file

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-22 11:51:10 -04:00
parent c3b2c8d8e5
commit 673fe04164
7 changed files with 283 additions and 53 deletions
+14 -14
View File
@@ -30,8 +30,8 @@ services:
container_name: cell-dns
command: ["-conf", "/etc/coredns/Corefile"]
ports:
- "53:53/udp"
- "53:53/tcp"
- "${DNS_PORT:-53}:53/udp"
- "${DNS_PORT:-53}:53/tcp"
volumes:
- ./config/dns/Corefile:/etc/coredns/Corefile
- ./data/dns:/data
@@ -50,7 +50,7 @@ services:
image: alpine:latest
container_name: cell-dhcp
ports:
- "67:67/udp"
- "${DHCP_PORT:-67}:67/udp"
volumes:
- ./config/dhcp/dnsmasq.conf:/etc/dnsmasq.conf
- ./data/dhcp:/var/lib/misc
@@ -72,7 +72,7 @@ services:
image: alpine:latest
container_name: cell-ntp
ports:
- "123:123/udp"
- "${NTP_PORT:-123}:123/udp"
volumes:
- ./config/ntp/chrony.conf:/etc/chrony/chrony.conf
restart: unless-stopped
@@ -96,9 +96,9 @@ services:
domainname: cell.local
env_file: ./config/mail/mailserver.env
ports:
- "25:25"
- "587:587"
- "993:993"
- "${MAIL_SMTP_PORT:-25}:25"
- "${MAIL_SUBMISSION_PORT:-587}:587"
- "${MAIL_IMAP_PORT:-993}:993"
volumes:
- ./data/maildata:/var/mail
- ./data/mailstate:/var/mail-state
@@ -122,7 +122,7 @@ services:
image: tomsquest/docker-radicale:latest
container_name: cell-radicale
ports:
- "5232:5232"
- "${RADICALE_PORT:-5232}:5232"
volumes:
- ./config/radicale:/etc/radicale
- ./data/radicale:/data
@@ -141,7 +141,7 @@ services:
image: bytemark/webdav:latest
container_name: cell-webdav
ports:
- "8080:80"
- "${WEBDAV_PORT:-8080}:80"
environment:
- AUTH_TYPE=Basic
- USERNAME=admin
@@ -167,7 +167,7 @@ services:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
ports:
- "51820:51820/udp"
- "${WG_PORT:-51820}:51820/udp"
volumes:
- ./config/wireguard:/config
- /lib/modules:/lib/modules
@@ -192,7 +192,7 @@ services:
build: ./api
container_name: cell-api
ports:
- "3000:3000"
- "${API_PORT:-3000}:3000"
volumes:
- ./data/api:/app/data
- ./data/dns:/app/data/dns
@@ -222,7 +222,7 @@ services:
build: ./webui
container_name: cell-webui
ports:
- "8081:80"
- "${WEBUI_PORT:-8081}:80"
restart: unless-stopped
networks:
cell-network:
@@ -242,7 +242,7 @@ services:
cell-network:
ipv4_address: ${RAINLOOP_IP:-172.20.0.12}
ports:
- "8888:8888"
- "${RAINLOOP_PORT:-8888}:8888"
volumes:
- ./data/rainloop:/rainloop/data
logging:
@@ -260,7 +260,7 @@ services:
cell-network:
ipv4_address: ${FILEGATOR_IP:-172.20.0.13}
ports:
- "8082:8080"
- "${FILEGATOR_PORT:-8082}:8080"
volumes:
- ./data/filegator:/var/www/filegator/private
logging: