give_subdomain only wrote an nginx vhost when app_type=='docker', so managed
PHP/static/python/flask/django apps got a Domain row but no route and stayed
reachable only at localhost:<port>. NginxService.create_site already had the
right templates for all of them.
Add a shared SiteDomainService.write_app_vhost(app, force_type=None) +
_vhost_create_kwargs mapper (docker/wordpress -> docker proxy,
flask/django/python -> proxy+static, php/static -> filesystem root; same
wildcard-cert selection as before) and route give_subdomain through it.
Collapse WordPressService._write_app_vhost into a thin delegate
(force_type='docker'), removing the duplicate with no behavior change.
Proven in test_dns_give_subdomain.py: php/static route from root, python
routes by port, and an unroutable app surfaces a warning instead of
silently faking success.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>