setup_cell.py now reads ip_range from cell_config.json before falling
back to CELL_IP_RANGE env var, so re-running make setup on an existing
install doesn't reset the .env subnet to the default 172.20.0.0/16.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
docker-compose.yml now uses ${VAR:-default} for every container IP and
the network subnet, so there are no hardcoded addresses in the YAML.
How it works:
- setup_cell.py generates .env at project root from ip_range (gitignored).
- docker-compose reads .env automatically at startup.
- When ip_range changes in Settings, the API writes a new .env via
ip_utils.write_env_file(); DNS/firewall/vIPs update immediately.
- User runs `make start` to recreate containers with the new IPs.
api/ip_utils.py gains ENV_VAR_NAMES dict and write_env_file(ip_range, path).
The old update_docker_compose_ips() direct-patch approach is removed from app.py.
3 new tests added (TestWriteEnvFile); total 324 pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
private_bytes_raw() was added later; fall back to private_bytes(Raw)
for older system packages (e.g. Debian Bookworm python3-cryptography).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
scripts/check_deps.sh now checks and installs all prerequisites:
git, curl, openssl, python3, python3-cryptography, docker, docker-compose.
Runs apt-get update only once if anything needs installing.
Also adds current user to docker group if missing.
Makefile calls it with sudo so it has the rights to install packages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Allows running make setup on hosts without wg binary or Python cryptography
library by passing pre-generated keys from another machine.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app.py: ConfigManager now uses CONFIG_DIR env var for config file path
instead of hardcoded './config/cell_config.json' — config was being read
from the image's working directory, making all settings writes ephemeral
(lost on container restart)
- wireguard_manager: generate_config uses configured address/port instead of
hardcoded 10.0.0.1 in DNAT rules and Address field
- scripts/setup_cell.py: full setup script — generates WireGuard keys (wg
binary or Python cryptography fallback), writes wg0.conf and cell_config.json
with correct _identity key; CELL_NAME / VPN_ADDRESS / WG_PORT env vars
- Makefile: setup target passes env vars through; build-api / build-webui targets
- README: replace install.sh references with make setup && make start
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>