# dirlist

Minimal directory listing web service, exposed publicly via a Cloudflare Tunnel
connector that runs **in the same Node process**. No root, no systemd, no
service-install needed.

## Quick start

```bash
npm install
npm start
```

If `.env` is missing, `index.js` falls back to `.env.example` automatically —
so the project boots with zero config right after install. To override
locally, copy `.env.example` to `.env` and edit it there:

```bash
cp .env.example .env   # only needed if you want local overrides
```

`npm start` boots:

1. The Express app on `PORT` (default 3000).
2. The `cloudflared` connector pointing to your existing named tunnel.

Both shut down together on `SIGINT` / `SIGTERM`.

## Environment variables

| Var | Default | Notes |
|-----|---------|-------|
| `CF_TUNNEL_TOKEN` | _required for tunnel_ | from Cloudflare Zero Trust dashboard |
| `PORT` | `3000` | |
| `HOST` | `0.0.0.0` | |
| `LISTING_ROOT` | parent of this project | absolute path, or relative to `dirlist/` |
| `SHOW_HIDDEN` | `0` | set `1` to show dotfiles |
| `INLINE_TEXT` | `0` | set `1` to render text files inline instead of downloading |
| `BASIC_AUTH_USER` / `BASIC_AUTH_PASS` | _disabled_ | both empty = no auth; both set = required |

Run without the tunnel (e.g. for local testing):

```bash
npm run app-only
# or
node index.js --no-tunnel
```

## Routes

- `GET /` — listing of the configured root
- `GET /<path>/` — listing of `<path>` under root
- `GET /<file>` — download (or inline-view for text files if `INLINE_TEXT=1`)

Path traversal (`..`, percent-encoded variants) is rejected.

## Deploy to a server (no root)

```bash
git clone <repo> dirlist
cd dirlist
npm install        # postinstall pulls the cloudflared binary for THIS host's OS
cp .env.example .env
$EDITOR .env       # set CF_TUNNEL_TOKEN, LISTING_ROOT
npm start          # or use PM2: pm2 start npm --name dirlist -- start
```

Because `cloudflared` is installed via npm, the binary download is automatic
and per-platform. Just run `npm install` on the target host.

### With PM2 (auto-restart, no root)

```bash
npm i -g pm2
pm2 start npm --name dirlist -- start
pm2 save
```

`pm2 startup` prints a sudo command — if you don't have root, skip it; PM2
will still resurrect on the same shell. For boot persistence without root,
use a `screen`/`tmux` session or whatever the platform provides.

## If the `cloudflared` npm package fails to install

The binary download in `cloudflared` postinstall can fail on locked-down hosts.
Manual fallback:

```bash
mkdir -p bin
curl -L -o bin/cloudflared \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
chmod +x bin/cloudflared
```

Then edit `index.js` `startTunnel()` to spawn `./bin/cloudflared tunnel run
--token <token>` instead of using the npm API. The `app.js` part is
unaffected.

## Files

```
dirlist/
├── index.js            Entry point — boots app + tunnel, handles signals
├── app.js              Express app (routes, helpers, traversal guard)
├── views/
│   └── listing.ejs     Single template for directory listings
├── package.json
├── .env.example
├── .gitignore
└── README.md
```