fix: /https/settings shows the https section and switches https.acme_staging, for the Router Manager.
Release / release (push) Successful in 56s

This commit is contained in:
slawek committed 2026-10-30 02:46:07 +01:00
1 parent f36e2a3b04
commit c2c33cfca0
5 files changed
+68 -3

No files matched your search

+3 -1
View File
@@ -537,7 +537,9 @@ unchanged. Both services always listen on `127.0.0.1` as well as on the interfac
never takes from the client. Let's Encrypt issues at most 5 certificates a week for the same never takes from the client. Let's Encrypt issues at most 5 certificates a week for the same
names, which routers rebuilt for tests reach; `https.acme_staging` sets Caddy's global `acme_ca` names, which routers rebuilt for tests reach; `https.acme_staging` sets Caddy's global `acme_ca`
to Let's Encrypt's staging directory, which replaces Caddy's default CAs for every site, so no to Let's Encrypt's staging directory, which replaces Caddy's default CAs for every site, so no
test certificate comes from a production CA. test certificate comes from a production CA. `PUT /https/settings` changes `acme_staging` alone:
the other settings of the section switch HTTPS off or move its ports, which would end the
connection the Router Manager makes the change on.
Consequences: HTTPS needs `wan.local_fqdn` in public DNS pointing at the router and port 80 Consequences: HTTPS needs `wan.local_fqdn` in public DNS pointing at the router and port 80
reachable from the internet; until then Caddy retries and the HTTPS ports do not answer. The reachable from the internet; until then Caddy retries and the HTTPS ports do not answer. The
+16 -1
View File
@@ -1018,7 +1018,7 @@ curl http://10.0.0.4:7081/status
### Tokens and signing in ### Tokens and signing in
`/config`, `/metrics/history`, `/metrics/settings`, `/users`, `/service-accounts`, `/groups`, `/site-to-site`, `/backup`, `/remote-access`, `/ca`, `/logs`, `/sites`, `/dns`, `/shell` and `/account` need a JWT in an `Authorization: Bearer` header, signed with `/config`, `/metrics/history`, `/metrics/settings`, `/https/settings`, `/users`, `/service-accounts`, `/groups`, `/site-to-site`, `/backup`, `/remote-access`, `/ca`, `/logs`, `/sites`, `/dns`, `/shell` and `/account` need a JWT in an `Authorization: Bearer` header, signed with
HS256 by the key the web service makes on its first run, `/etc/vpn-router/web.key` (root only). HS256 by the key the web service makes on its first run, `/etc/vpn-router/web.key` (root only).
The key never leaves the router; while it does not exist these paths and `/auth` are not served The key never leaves the router; while it does not exist these paths and `/auth` are not served
(404). A missing, expired or wrongly signed token, or one of another algorithm, gets 401 with (404). A missing, expired or wrongly signed token, or one of another algorithm, gets 401 with
@@ -1405,6 +1405,18 @@ A change is made, checked and applied as for `/site-to-site`.
A change is made, checked and applied as for `/site-to-site`. A change is made, checked and applied as for `/site-to-site`.
### The /https/settings API
`/https/settings` shows the settings of HTTPS and changes the CA of Caddy's certificates, with the
same token as `/users`.
| Request | Body | Answer |
| --- | --- | --- |
| `GET /https/settings` | | `{"settings"}`: the `https` section |
| `PUT /https/settings` | `{"acme_staging"}`; any other setting of the `https` section is 400, as it is changed on the router with `vpn-config-edit` | `{"settings"}` |
A change is made, checked and applied as for `/site-to-site`.
### The /remote-access API ### The /remote-access API
`/remote-access` shows and changes the remote access systems, IKEv2 (`p2s`), `/remote-access` shows and changes the remote access systems, IKEv2 (`p2s`),
@@ -1484,6 +1496,9 @@ obtains from an ACME CA, those of the web sites with `tls` `acme` included.
vpn-config-edit set --restart https.acme_staging true vpn-config-edit set --restart https.acme_staging true
``` ```
The Router Manager switches it on the Overview, and `PUT /https/settings` changes it (see The
/https/settings API).
`vpn-router-setup` writes Caddy's configuration to `/etc/caddy/vpn-router.Caddyfile` (root, group `vpn-router-setup` writes Caddy's configuration to `/etc/caddy/vpn-router.Caddyfile` (root, group
`caddy`, the group Caddy runs as, mode 0640), which the `caddy`, the group Caddy runs as, mode 0640), which the
package's drop-in `/usr/lib/systemd/system/caddy.service.d/vpn-router.conf` makes `caddy.service` package's drop-in `/usr/lib/systemd/system/caddy.service.d/vpn-router.conf` makes `caddy.service`
+10
View File
@@ -1,3 +1,13 @@
vpn-router (0.38.1-1) unstable; urgency=medium
fix: /https/settings shows the https section and switches https.acme_staging, for the Router Manager.
* GET /https/settings shows the https section, and PUT /https/settings
changes acme_staging; the other settings of the section stay with
vpn-config-edit.
-- Slawomir Koszewski <slawek@koszewscy.waw.pl> Fri, 30 Oct 2026 02:43:22 +0100
vpn-router (0.38.0-1) unstable; urgency=medium vpn-router (0.38.0-1) unstable; urgency=medium
feature: https.acme_staging takes Caddy's certificates from Let's Encrypt's staging environment. feature: https.acme_staging takes Caddy's certificates from Let's Encrypt's staging environment.
@@ -22,6 +22,7 @@ from .connectivity import remote_access, site_to_site
from .dns import dns from .dns import dns
from .identities import account, groups, service_accounts, users from .identities import account, groups, service_accounts, users
from .logs import logs from .logs import logs
from .https import https_settings
from .metrics import metrics_history, metrics_settings from .metrics import metrics_history, metrics_settings
from .pki import PUBLISHED, ca from .pki import PUBLISHED, ca
from .shell import EDITOR_BODY_LIMIT, shell, shell_editor, shell_passkey, shell_ticket from .shell import EDITOR_BODY_LIMIT, shell, shell_editor, shell_passkey, shell_ticket
@@ -66,7 +67,8 @@ class Handler(BaseHTTPRequestHandler):
directory = next((name for name in ('users', 'service-accounts', 'groups', 'account', 'site-to-site', 'backup', directory = next((name for name in ('users', 'service-accounts', 'groups', 'account', 'site-to-site', 'backup',
'ca', 'shell', 'remote-access', 'logs', 'sites', 'dns') 'ca', 'shell', 'remote-access', 'logs', 'sites', 'dns')
if path == f'/{name}' or path.startswith(f'/{name}/')), None) if path == f'/{name}' or path.startswith(f'/{name}/')), None)
protected = path in ('/status/full', '/config', '/metrics/history', '/metrics/settings', '/postgresql') or \ protected = path in ('/status/full', '/config', '/metrics/history', '/metrics/settings', '/https/settings',
'/postgresql') or \
directory is not None directory is not None
signing = path in ('/auth', '/auth/passkey', '/auth/passkey/complete', '/auth/refresh', '/auth/logout') signing = path in ('/auth', '/auth/passkey', '/auth/passkey/complete', '/auth/refresh', '/auth/logout')
oidc = (path == '/.well-known/openid-configuration' or path.startswith('/oidc/')) and \ oidc = (path == '/.well-known/openid-configuration' or path.startswith('/oidc/')) and \
@@ -113,6 +115,9 @@ class Handler(BaseHTTPRequestHandler):
elif path == '/metrics/settings': elif path == '/metrics/settings':
code, document = metrics_settings(self.command, payload) code, document = metrics_settings(self.command, payload)
body, kind = json.dumps(document, indent=2).encode() + b'\n', 'application/json' body, kind = json.dumps(document, indent=2).encode() + b'\n', 'application/json'
elif path == '/https/settings':
code, document = https_settings(self.command, payload)
body, kind = json.dumps(document, indent=2).encode() + b'\n', 'application/json'
elif directory == 'shell' and (path, self.command) == ('/shell', 'GET'): elif directory == 'shell' and (path, self.command) == ('/shell', 'GET'):
return shell(self, claims.get('sub')) return shell(self, claims.get('sub'))
elif directory == 'shell' and path.startswith('/shell/editor/'): elif directory == 'shell' and path.startswith('/shell/editor/'):
@@ -0,0 +1,33 @@
"""/https/settings: the settings of HTTPS, of which the API changes the CA of Caddy's certificates."""
import vpnrouter
from .common import section_change
#: The settings of the https section PUT /https/settings changes.
CHANGEABLE = ('acme_staging',)
def https_settings(method, body):
"""Answer a /https/settings request: the HTTP status and the JSON document.
GET /https/settings {"settings"}: the https section
PUT /https/settings change acme_staging; the other settings of the section are changed on the router with
vpn-config-edit, and a body naming one is 400
A change is applied by restarting vpn-router-setup without waiting for it.
"""
if body == 'invalid' or (body is not None and not isinstance(body, dict)):
return 400, {'error': 'the body must be a JSON object'}
if method in ('GET', 'HEAD'):
try:
return 200, {'settings': vpnrouter.load_config()['https']}
except SystemExit as exc:
return 500, {'error': str(exc.code)}
if method != 'PUT':
return 404, {'error': f'no route {method} /https/settings'}
others = sorted(set(body or {}) - set(CHANGEABLE))
if others:
return 400, {'error': f'https.{", https.".join(others)}: changed on the router with vpn-config-edit only'}
changed = section_change('https', body or {})
return changed if isinstance(changed, tuple) else (200, {'settings': changed})