Lightweight local HTTP file server with plugin support. Serves static files from a webroot, mounts plugin directories at URL prefixes via config, and runs index.py entry points as CGI.
Installs into .claude/skills of the current project.
Sponsors
SSkills DirectorySkills Directory
Is that skill safe to install?
SSkills DirectorySkills Directory
Know which skills are safe โ weekly.
Are you the author of Intranet?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/modbender-intranet)
---
name: intranet
description: "Lightweight local HTTP file server with plugin support. Serves static files from a webroot, mounts plugin directories at URL prefixes via config, and runs index.py entry points as CGI."
summary: "Local HTTP file server with config-based plugins and CGI support."
version: 3.2.5
homepage: https://github.com/odrobnik/intranet-skill
metadata:
openclaw:
emoji: "๐"
requires:
bins: ["python3"]
---
# Intranet
Lightweight local HTTP file server โ no Apache/nginx needed, no root required. Serves static files, mounts plugin directories, and runs `index.py` entry points as CGI.
**Entry point:** `{baseDir}/scripts/intranet.py`
## Setup
See [SETUP.md](SETUP.md) for prerequisites and setup instructions.
## Commands
```bash
python3 {baseDir}/scripts/intranet.py start # Start on default port 8080
python3 {baseDir}/scripts/intranet.py start --port 9000 # Custom port
python3 {baseDir}/scripts/intranet.py start --host 0.0.0.0 # LAN access (requires token + allowed_hosts)
python3 {baseDir}/scripts/intranet.py start --token SECRET # Enable bearer token auth
python3 {baseDir}/scripts/intranet.py status # Check if running
python3 {baseDir}/scripts/intranet.py stop # Stop server
```
## Directory Layout
```
{workspace}/intranet/
โโโ config.json # Server config (NOT served)
โโโ www/ # Webroot (served files go here)
โโโ index.html
โโโ ...
```
Config lives in `{workspace}/intranet/config.json`, webroot is `{workspace}/intranet/www/`. The config file is never exposed to HTTP.
## Plugins
Plugins mount external directories at URL prefixes. Configure in `config.json`:
```json
{
"plugins": {
"banker": "/path/to/banker",
"deliveries": "/path/to/deliveries"
}
}
```
Plugin config supports simple (static only) or extended (with CGI hash) format:
```json
{
"plugins": {
"static-only": "/path/to/dir",
"with-cgi": {
"dir": "/path/to/dir",
"hash": "sha256:abc123..."
}
}
}
```
- Plugin paths must be inside the workspace
- If CGI is enabled and a plugin has a `hash`, `index.py` at the plugin root handles all sub-paths โ but only if its SHA-256 matches
- Plugins without a `hash` are static-only (CGI blocked even when globally enabled)
- Generate a hash: `shasum -a 256 /path/to/index.py`
## CGI Execution
**Off by default.** Enable in `config.json`:
```json
{
"cgi": true
}
```
When enabled, only files named `index.py` can execute as CGI:
- **Webroot**: `index.py` in any subdirectory handles that directory's requests
- **Plugins**: `index.py` at the plugin root handles all plugin sub-paths
- **All other `.py` files** โ 403 Forbidden (never served, never executed)
- Scripts must have the executable bit set (`chmod +x`)
## Security
- **Webroot isolation** โ config.json is outside the webroot (`www/`), never served
- **CGI off by default** โ must be explicitly enabled via `"cgi": true` in config.json
- **Path containment** โ all resolved paths must stay within their base directory. Symlinks are followed but the resolved target is checked for containment.
- **Plugin allowlist** โ only directories explicitly registered in `config.json` are served; must be inside workspace
- **CGI restricted to `index.py`** โ no arbitrary script execution; plugin CGI requires SHA-256 hash in config.json
- **All `.py` files blocked** except `index.py` entry points (not served as text, not executed)
- **Host allowlist** โ optional `allowed_hosts` restricts which `Host` headers are accepted
- **Token auth** โ optional bearer token via `--token` flag or `config.json`. Browser clients visit `?token=SECRET` once โ session cookie set โ all subsequent navigation works. API clients use `Authorization: Bearer <token>` header.
- **Path traversal protection** โ all paths resolved and validated before serving
- **Default bind: `127.0.0.1`** (loopback only). LAN access via `--host 0.0.0.0` requires both token auth and `allowed_hosts` in config.json.
## Notes
- All state files are inside the workspace:
- Config: `{workspace}/intranet/config.json`
- PID: `{workspace}/intranet/.pid`
- Runtime: `{workspace}/intranet/.conf`
- Webroot: `{workspace}/intranet/www/`
- No files are written outside the workspace
- 30-second timeout on CGI execution (when enabled)