docs: update zellij-ps to reflect project switcher functionality
- Update package description and fix mainProgram typo - Rewrite documentation to describe project switching, not process viewing - Add PROJECT_FOLDERS configuration and usage examples - Update all references across docs (README, guides, module overviews)
This commit is contained in:
525
docs/guides/port-management.md
Normal file
525
docs/guides/port-management.md
Normal file
@@ -0,0 +1,525 @@
|
||||
# Port Management Guide
|
||||
|
||||
Managing service ports across multiple hosts with the `m3ta.ports` module.
|
||||
|
||||
## Overview
|
||||
|
||||
The port management module provides a centralized way to define service ports that can have host-specific overrides. This prevents port conflicts and makes it easy to manage services across multiple machines.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Enable Port Management
|
||||
|
||||
```nix
|
||||
{config, ...}: {
|
||||
m3ta.ports = {
|
||||
enable = true;
|
||||
|
||||
# Define default ports
|
||||
definitions = {
|
||||
nginx = 80;
|
||||
grafana = 3000;
|
||||
prometheus = 9090;
|
||||
homepage = 8080;
|
||||
};
|
||||
|
||||
# Define host-specific overrides
|
||||
hostOverrides = {
|
||||
laptop = {
|
||||
nginx = 8080; # Override on laptop
|
||||
homepage = 3001; # Override on laptop
|
||||
};
|
||||
server = {
|
||||
homepage = 3002; # Override on server
|
||||
};
|
||||
};
|
||||
|
||||
# Set current host (determines which overrides to use)
|
||||
currentHost = config.networking.hostName;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Using Ports
|
||||
|
||||
```nix
|
||||
{config, ...}: {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
httpConfig = ''
|
||||
server {
|
||||
listen ${toString (config.m3ta.ports.get "nginx")};
|
||||
root /var/www;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
services.grafana = {
|
||||
enable = true;
|
||||
settings.server.http_port = config.m3ta.ports.get "grafana";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Module Options
|
||||
|
||||
### `m3ta.ports.enable`
|
||||
|
||||
Enable port management module.
|
||||
|
||||
- Type: `boolean`
|
||||
- Default: `false`
|
||||
|
||||
### `m3ta.ports.definitions`
|
||||
|
||||
Default port definitions.
|
||||
|
||||
- Type: `attrsOf int`
|
||||
- Default: `{}`
|
||||
|
||||
```nix
|
||||
definitions = {
|
||||
nginx = 80;
|
||||
grafana = 3000;
|
||||
prometheus = 9090;
|
||||
};
|
||||
```
|
||||
|
||||
### `m3ta.ports.hostOverrides`
|
||||
|
||||
Host-specific port overrides.
|
||||
|
||||
- Type: `attrsOf (attrsOf int)`
|
||||
- Default: `{}`
|
||||
|
||||
```nix
|
||||
hostOverrides = {
|
||||
laptop = {
|
||||
nginx = 8080;
|
||||
grafana = 3001;
|
||||
};
|
||||
server = {
|
||||
grafana = 3002;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### `m3ta.ports.currentHost`
|
||||
|
||||
Current hostname. Determines which overrides to apply.
|
||||
|
||||
- Type: `string`
|
||||
- Example: `config.networking.hostName`
|
||||
|
||||
```nix
|
||||
currentHost = "laptop"; # Use laptop overrides
|
||||
```
|
||||
|
||||
### `m3ta.ports.generateEnvVars` (Home Manager only)
|
||||
|
||||
Generate environment variables from ports.
|
||||
|
||||
- Type: `boolean`
|
||||
- Default: `false` (Home Manager)
|
||||
- NixOS: Not available
|
||||
|
||||
When enabled, generates environment variables like:
|
||||
- `PORT_NGINX=8080`
|
||||
- `PORT_GRAFANA=3000`
|
||||
|
||||
## Functions
|
||||
|
||||
### `config.m3ta.ports.get "service"`
|
||||
|
||||
Get port for a service with host-specific override.
|
||||
|
||||
```nix
|
||||
services.nginx = {
|
||||
port = config.m3ta.ports.get "nginx";
|
||||
};
|
||||
```
|
||||
|
||||
If current host is `laptop` and `hostOverrides.laptop.nginx = 8080`, returns `8080`.
|
||||
If no override, returns default `80`.
|
||||
|
||||
### `config.m3ta.ports.getHostPorts "hostname"`
|
||||
|
||||
Get all ports for a specific host.
|
||||
|
||||
```nix
|
||||
# Get all ports for laptop
|
||||
laptopPorts = config.m3ta.ports.getHostPorts "laptop";
|
||||
# Returns: { nginx = 8080; grafana = 3000; ... }
|
||||
```
|
||||
|
||||
### `config.m3ta.ports.listServices`
|
||||
|
||||
List all defined service names.
|
||||
|
||||
```nix
|
||||
allServices = config.m3ta.ports.listServices;
|
||||
# Returns: ["nginx" "grafana" "prometheus" "homepage"]
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### NixOS Configuration
|
||||
|
||||
```nix
|
||||
{config, ...}: {
|
||||
# Define ports
|
||||
m3ta.ports = {
|
||||
enable = true;
|
||||
definitions = {
|
||||
nginx = 80;
|
||||
grafana = 3000;
|
||||
prometheus = 9090;
|
||||
loki = 3100;
|
||||
promtail = 9080;
|
||||
};
|
||||
hostOverrides.laptop = {
|
||||
nginx = 8080;
|
||||
grafana = 3001;
|
||||
};
|
||||
currentHost = config.networking.hostName;
|
||||
};
|
||||
|
||||
# Use ports
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
httpConfig = ''
|
||||
server {
|
||||
listen ${toString (config.m3ta.ports.get "nginx")};
|
||||
root /var/www;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
services.grafana = {
|
||||
enable = true;
|
||||
settings.server.http_port = config.m3ta.ports.get "grafana";
|
||||
};
|
||||
|
||||
services.prometheus = {
|
||||
enable = true;
|
||||
port = config.m3ta.ports.get "prometheus";
|
||||
};
|
||||
|
||||
services.loki = {
|
||||
enable = true;
|
||||
configuration.http_listen_port = config.m3ta.ports.get "loki";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Home Manager Configuration
|
||||
|
||||
```nix
|
||||
{config, ...}: {
|
||||
# Define ports
|
||||
m3ta.ports = {
|
||||
enable = true;
|
||||
definitions = {
|
||||
dev-server = 3000;
|
||||
nextjs = 3001;
|
||||
vite = 5173;
|
||||
};
|
||||
hostOverrides.desktop = {
|
||||
vite = 5174;
|
||||
};
|
||||
currentHost = "desktop";
|
||||
generateEnvVars = true; # Generate env vars
|
||||
};
|
||||
|
||||
# Ports are now available as env vars
|
||||
# PORT_DEV_SERVER=3000
|
||||
# PORT_NEXTJS=3001
|
||||
# PORT_VITE=5174
|
||||
|
||||
home.sessionVariables = {
|
||||
DEV_PORT = toString (config.m3ta.ports.get "dev-server");
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### With Custom Modules
|
||||
|
||||
Using ports with custom modules (e.g., `m3ta.mem0`):
|
||||
|
||||
```nix
|
||||
{config, ...}: {
|
||||
# Define ports
|
||||
m3ta.ports = {
|
||||
enable = true;
|
||||
definitions = {
|
||||
mem0 = 8000;
|
||||
qdrant = 6333;
|
||||
};
|
||||
hostOverrides.laptop = {
|
||||
mem0 = 8080;
|
||||
};
|
||||
currentHost = config.networking.hostName;
|
||||
};
|
||||
|
||||
# Use with mem0 module
|
||||
m3ta.mem0 = {
|
||||
enable = true;
|
||||
port = config.m3ta.ports.get "mem0"; # 8000 or 8080 on laptop
|
||||
};
|
||||
|
||||
# Use with qdrant service
|
||||
services.qdrant = {
|
||||
enable = true;
|
||||
port = config.m3ta.ports.get "qdrant";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Port File Generation
|
||||
|
||||
Generate a JSON file with all ports:
|
||||
|
||||
```nix
|
||||
{config, pkgs, ...}: {
|
||||
m3ta.ports = {
|
||||
enable = true;
|
||||
definitions = {
|
||||
service1 = 80;
|
||||
service2 = 443;
|
||||
};
|
||||
currentHost = config.networking.hostName;
|
||||
};
|
||||
|
||||
# Generate port file
|
||||
environment.etc."m3ta/ports.json".text = builtins.toJSON (
|
||||
config.m3ta.ports.getHostPorts config.networking.hostName
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Conditional Configuration
|
||||
|
||||
```nix
|
||||
{config, ...}: {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
# Only open firewall if binding to non-localhost
|
||||
httpConfig = let
|
||||
port = config.m3ta.ports.get "nginx";
|
||||
in ''
|
||||
server {
|
||||
listen ${toString port};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts =
|
||||
if config.m3ta.ports.get "nginx" == 80
|
||||
then [80]
|
||||
else [];
|
||||
}
|
||||
```
|
||||
|
||||
### Port Ranges
|
||||
|
||||
```nix
|
||||
definitions = {
|
||||
service-start = 8000;
|
||||
service-end = 8999;
|
||||
};
|
||||
|
||||
# Use in config
|
||||
services.my-app = {
|
||||
portRange = [
|
||||
config.m3ta.ports.get "service-start"
|
||||
config.m3ta.ports.get "service-end"
|
||||
];
|
||||
};
|
||||
```
|
||||
|
||||
### Dynamic Port Allocation
|
||||
|
||||
```nix
|
||||
{config, ...}: {
|
||||
m3ta.ports = {
|
||||
enable = true;
|
||||
definitions = {
|
||||
# Reserve port ranges
|
||||
app-range-start = 9000;
|
||||
app-range-end = 9999;
|
||||
};
|
||||
currentHost = config.networking.hostName;
|
||||
};
|
||||
|
||||
# Calculate next available port
|
||||
services.my-app = {
|
||||
port = config.m3ta.ports.get "app-range-start" + 0;
|
||||
};
|
||||
|
||||
services.my-other-app = {
|
||||
port = config.m3ta.ports.get "app-range-start" + 1;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Use Descriptive Service Names
|
||||
|
||||
```nix
|
||||
# Good
|
||||
definitions = {
|
||||
nginx = 80;
|
||||
grafana = 3000;
|
||||
prometheus-ui = 9090;
|
||||
prometheus-push = 9091;
|
||||
};
|
||||
|
||||
# Avoid
|
||||
definitions = {
|
||||
p1 = 80;
|
||||
p2 = 3000;
|
||||
p3 = 9090;
|
||||
};
|
||||
```
|
||||
|
||||
### Group Related Services
|
||||
|
||||
```nix
|
||||
definitions = {
|
||||
# Monitoring stack
|
||||
grafana = 3000;
|
||||
prometheus = 9090;
|
||||
loki = 3100;
|
||||
promtail = 9080;
|
||||
|
||||
# Web services
|
||||
nginx = 80;
|
||||
homepage = 8080;
|
||||
|
||||
# Databases
|
||||
postgres = 5432;
|
||||
redis = 6379;
|
||||
qdrant = 6333;
|
||||
};
|
||||
```
|
||||
|
||||
### Document Overrides
|
||||
|
||||
```nix
|
||||
hostOverrides = {
|
||||
# Laptop: Running multiple dev servers, use higher ports
|
||||
laptop = {
|
||||
nginx = 8080;
|
||||
dev-server = 3000;
|
||||
};
|
||||
|
||||
# Server: Production, use standard ports
|
||||
server = {
|
||||
nginx = 80;
|
||||
dev-server = null; # Disable on server
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Handle Missing Ports
|
||||
|
||||
```nix
|
||||
services.some-service = {
|
||||
enable = true;
|
||||
port = config.m3ta.ports.get "some-service" or 8080;
|
||||
};
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Service Not Found
|
||||
|
||||
Error: `Service "foo" not defined`
|
||||
|
||||
Solution: Add service to `definitions`:
|
||||
|
||||
```nix
|
||||
definitions = {
|
||||
foo = 8080;
|
||||
};
|
||||
```
|
||||
|
||||
### Current Host Not Set
|
||||
|
||||
Error: `currentHost not set`
|
||||
|
||||
Solution: Set `currentHost`:
|
||||
|
||||
```nix
|
||||
currentHost = config.networking.hostName;
|
||||
```
|
||||
|
||||
### Port Conflict
|
||||
|
||||
Issue: Two services trying to use same port.
|
||||
|
||||
Solution: Define both in port management:
|
||||
|
||||
```nix
|
||||
definitions = {
|
||||
service1 = 8080;
|
||||
service2 = 8081; # Different port
|
||||
};
|
||||
```
|
||||
|
||||
## Migration from Hardcoded Ports
|
||||
|
||||
### Before
|
||||
|
||||
```nix
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
httpConfig = ''
|
||||
server {
|
||||
listen 80;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
services.grafana = {
|
||||
enable = true;
|
||||
settings.server.http_port = 3000;
|
||||
};
|
||||
```
|
||||
|
||||
### After
|
||||
|
||||
```nix
|
||||
m3ta.ports = {
|
||||
enable = true;
|
||||
definitions = {
|
||||
nginx = 80;
|
||||
grafana = 3000;
|
||||
};
|
||||
currentHost = config.networking.hostName;
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
httpConfig = ''
|
||||
server {
|
||||
listen ${toString (config.m3ta.ports.get "nginx")};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
services.grafana = {
|
||||
enable = true;
|
||||
settings.server.http_port = config.m3ta.ports.get "grafana";
|
||||
};
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Architecture](../ARCHITECTURE.md) - Understanding the library functions
|
||||
- [Using Modules](./using-modules.md) - Using modules with port management
|
||||
- [Contributing](../CONTRIBUTING.md) - Code style and guidelines
|
||||
Reference in New Issue
Block a user