nixos/cliproxyapi: use v8 config layout

Signed-off-by: Anish Pallati <i@anish.land>
This commit is contained in:
Anish Pallati
2026-09-29 19:25:05 -04:00
parent 82966f9018
commit 2deb6bc2cf
3 changed files with 50 additions and 25 deletions

View File

@@ -1,6 +1,6 @@
# CLIProxyAPI {#module-services-cliproxyapi}
[CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) exposes OAuth-based subscription CLIs (Claude Code, Codex, Gemini, Qwen, Grok, Antigravity) behind OpenAI/Gemini/Anthropic-compatible HTTP APIs.
[CLIProxyAPI](https://github.com/router-for-me/CLIProxyAPI) exposes OAuth-based subscription CLIs (Claude Code, Codex, Grok, Antigravity, Kimi, Devin, Meta) behind OpenAI/Gemini/Anthropic-compatible HTTP APIs.
Enable it with:
@@ -10,11 +10,11 @@ Enable it with:
}
```
The service runs as a dedicated `cliproxyapi` user and keeps its configuration and OAuth tokens under `/var/lib/cliproxyapi`.
The service runs as a dedicated `cliproxyapi` user and keeps its configuration and OAuth tokens under `/var/lib/cliproxyapi`. The configuration file is regenerated from [](#opt-services.cliproxyapi.settings) at startup, which overwrites any changes made through the management API.
## Authentication {#module-services-cliproxyapi-authentication}
Provider logins use OAuth and must land in the service's `auth-dir` (`/var/lib/cliproxyapi`), which is owned by the `cliproxyapi` user. Either of the approaches below writes the token with the correct ownership, and the running service picks it up without a restart.
Provider logins use OAuth and must land in the service's `oauth.auth-dir` (`/var/lib/cliproxyapi`), which is owned by the `cliproxyapi` user. Either of the approaches below writes the token with the correct ownership, and the running service picks it up without a restart.
### Management API {#module-services-cliproxyapi-authentication-management-api}
@@ -22,19 +22,31 @@ Set a management key in [](#opt-services.cliproxyapi.settings):
```nix
{
services.cliproxyapi.settings.remote-management.secret-key._secret =
"/run/secrets/cliproxyapi-mgmt-key";
services.cliproxyapi.settings.management.secret-key._secret = "/run/secrets/cliproxyapi-mgmt-key";
}
```
Then request an authentication URL for the desired provider and open it in a browser:
Request a login URL and open it in a browser:
```bash
curl -H "Authorization: Bearer <management-key>" \
http://127.0.0.1:8317/v0/management/anthropic-auth-url
"http://127.0.0.1:8317/v8/management/oauth/auth-url?provider=claude"
```
The daemon completes the OAuth flow itself and stores the token in its `auth-dir`. Authentication endpoints are available for the `anthropic`, `codex`, `xai`, `antigravity`, and `kimi` providers.
Other values for `provider` are `codex`, `antigravity`, `kimi`, `kimi-ai`, `xai`, `devin` and `meta`. `kimi`, `kimi-ai`, `xai` and `meta` use a device code, so the login finishes once it is approved in the browser.
For `claude`, `codex` and `antigravity`, the browser ends up on a `localhost` page that fails to load. Send that URL to the daemon to finish the login:
```bash
curl -H "Authorization: Bearer <management-key>" \
-H "Content-Type: application/json" \
-d '{"redirect_url": "<url>"}' \
http://127.0.0.1:8317/v8/management/oauth/callback
```
Alternatively, add `is_webui=true` to the login URL request, and the daemon will listen on the callback port and finish the login itself.
To check on a login, query `/v8/management/oauth/status?state=<state>` with the `state` from the login URL response. It returns `wait` while the login is pending, `ok` once the token is saved and `error` if it failed.
### Command-line login {#module-services-cliproxyapi-authentication-cli}
@@ -52,4 +64,4 @@ Then run the login as the service user, pointing at the managed configuration:
sudo -u cliproxyapi cliproxyapi -config /var/lib/cliproxyapi/config.yaml --claude-login
```
Other providers use their matching flags, for example `--codex-login` or `--xai-login`. On a headless host, pass `-no-browser` to print the OAuth URL instead of launching a browser.
Other providers have their own flags, such as `--codex-login` or `--xai-login`; see `cliproxyapi -help`. On a headless host, add `-no-browser` to print the login URL. The Claude, Codex, Antigravity and Devin logins then ask you to paste the `localhost` URL you were redirected to.

View File

@@ -10,14 +10,9 @@ let
format = pkgs.formats.yaml { };
stateDir = "/var/lib/cliproxyapi";
configPath = "${stateDir}/config.yaml";
settings = {
auth-dir = stateDir;
}
// cfg.settings;
secretsReplacement = utils.genJqSecretsReplacement {
loadCredential = true;
} settings configPath;
port = cfg.settings.port or 8317;
} cfg.settings configPath;
in
{
options.services.cliproxyapi = {
@@ -26,14 +21,30 @@ in
package = lib.mkPackageOption pkgs "cliproxyapi" { };
settings = lib.mkOption {
type = format.type;
type = lib.types.submodule {
freeformType = format.type;
options = {
server.port = lib.mkOption {
type = lib.types.port;
default = 8317;
description = "Port on which CLIProxyAPI listens.";
};
oauth.auth-dir = lib.mkOption {
type = lib.types.str;
default = stateDir;
description = "Directory where OAuth tokens are stored.";
};
};
};
default = { };
example = lib.literalExpression ''
{
host = "127.0.0.1";
port = 8317;
api-keys = [ { _secret = "/run/secrets/cliproxyapi-api-key"; } ];
remote-management.secret-key._secret = "/run/secrets/cliproxyapi-management-key";
server = {
host = "127.0.0.1";
port = 8317;
};
access.api-keys = [ { _secret = "/run/secrets/cliproxyapi-api-key"; } ];
management.secret-key._secret = "/run/secrets/cliproxyapi-management-key";
}
'';
description = ''
@@ -54,7 +65,7 @@ in
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to open the firewall for the specified port.";
description = "Whether to open the firewall for {option}`services.cliproxyapi.settings.server.port`.";
};
user = lib.mkOption {
@@ -142,7 +153,7 @@ in
};
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ port ];
allowedTCPPorts = [ cfg.settings.server.port ];
};
};

View File

@@ -10,9 +10,11 @@
services.cliproxyapi = {
enable = true;
settings = {
host = "127.0.0.1";
port = 8317;
api-keys = [ { _secret = "/etc/cliproxyapi-api-key"; } ];
server = {
host = "127.0.0.1";
port = 8317;
};
access.api-keys = [ { _secret = "/etc/cliproxyapi-api-key"; } ];
};
};