-
Notifications
You must be signed in to change notification settings - Fork 0
Mac self‐hosting
- PHP (Mac often has it already — check with
php -vin Terminal) - A public HTTPS URL (tunnel) so Litter Layer can reach your Mac — e.g. Cloudflare Tunnel or ngrok
- The starter pack from litterlayer.com/federation/
- No PHP? Install with Homebrew:
brew install php
Unzip the starter pack, e.g. ~/Sites/my-node/:
my-node/
.well-known/litterlayer.json
sites.json
search.php
crawl_tick.php
ll-widget.js
lib/
ll_node_common.php
ll_node_crawler.php
data/ (must be writable by PHP)
.htaccess
.well-known/litterlayer.json — your public HTTPS URL (not localhost):
{
"node_id": "my-node.example.com",
"base_url": "https://my-node.example.com",
"categories": ["writing", "tech"],
"capabilities": { "search": true },
"performance": { "timeout_ms": 1200 }
}
Optional: if your node files live in a subfolder (e.g. https://example.com/test/) but your website is at the domain root, you do not need to change anything — the auto-crawler seeds from https://example.com/sitemap.xml and / by default. To crawl a subfolder only, add:
"crawl_root_url": "https://example.com/test"
sites.json — pages you want searchable (url, title, description, score). You can also leave a minimal list and let the auto-crawler fill this file over time (see step 6).
[
{
"url": "https://wilcosky.com/",
"title": "wilcosky.com",
"description": "Personal site of Billy Wilcosky — writing, projects, and links on the small web.",
"score": 1.0
},
{
"url": "http://www.internetlastpage.com/",
"title": "The Last Page of the Internet",
"description": "Ta Da! You have reached the very last page of the Internet. Turn off your computer and go have fun.",
"score": 0.9
}
]
Auto-crawled pages get a default score of 0.8. Manual scores are kept on re-crawl.
Open Terminal, go to your folder, start the built-in server:
cd ~/Sites/my-node
php -S localhost:8080
Leave that window open while testing.
Alternative: MAMP — set the document root to my-node and use MAMP’s port (often 8888).
Make sure the data/ folder is writable by PHP.
Your Mac isn’t reachable from the internet by default. Use a tunnel:
ngrok (quick test):
brew install ngrok
ngrok http 8080
Copy the https://….ngrok-free.app URL.
Cloudflare Tunnel — good for a stable URL if you have a domain.
Put that HTTPS URL in litterlayer.json as base_url.
Note: php -S doesn’t read .htaccess, so /search and /crawl_tick may not work until you use MAMP/Apache, a router script, or Nginx. For registration, the hub calls https://your-url/search — Apache + .htaccess, or MAMP with mod_rewrite, is the reliable Mac setup.
Save as router.php in my-node/:
<?php
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if ($uri === '/search') {
require __DIR__ . '/search.php';
return true;
}
if ($uri === '/crawl_tick') {
require __DIR__ . '/crawl_tick.php';
return true;
}
return false;Run:
php -S localhost:8080 router.php
Point root at your folder and add /search and /crawl_tick rules:
server {
listen 443 ssl;
server_name my-node.example.com;
root /var/www/my-node;
index index.html;
# SSL cert paths here (certbot, etc.)
location = /.well-known/litterlayer.json {
default_type application/json;
try_files /litterlayer.json =404;
}
location = /search {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/search.php;
fastcgi_pass unix:/opt/homebrew/var/run/php-fpm.sock; # Homebrew PHP-FPM socket
}
location = /crawl_tick {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/crawl_tick.php;
fastcgi_pass unix:/opt/homebrew/var/run/php-fpm.sock;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/opt/homebrew/var/run/php-fpm.sock;
}
}
Descriptor (Safari/Chrome):
https://your-url/.well-known/litterlayer.json
Search (Terminal):
curl -sS -X POST https://your-url/search \
-H "Content-Type: application/json" \
-d '{"query":"hello","limit":5}'
→ expect {"results":[...], ...}
Crawl tick (Terminal, optional auto-crawler):
curl -sS https://your-url/crawl_tick
→ expect JSON like {"ok":true,...} (or "skipped":"throttled" if called again within 5 minutes)
The starter pack includes a search box for your own site (not Litter Layer’s index). It uses the same sites.json as federated search.
Embed on any page on your domain (same origin as the node files):
<div id="ll-site-search"></div>
<script src="/ll-widget.js" defer></script>Point src at wherever you uploaded ll-widget.js. If your node lives in a subfolder, use e.g. src="/test/ll-widget.js" — the widget finds /search and /crawl_tick relative to that script.
What happens when someone visits the page:
- The widget searches your local
/searchendpoint (25 results per page, Load more for the next page). - A background crawl tick runs (at most once every 5 minutes, 2 pages per tick).
- The crawler tries
https://yoursite.com/sitemap.xml, then your homepage at/, then follows same-domain links. - Discovered pages are merged into
sites.json(manual entries are kept). No cron job required.
Mac note: your tunnel must be running and the page with the widget must be reachable over HTTPS for crawls to advance. Testing with curl /crawl_tick also works.
Go to litterlayer.com/federation/ and submit:
https://your-url/.well-known/litterlayer.json
Wait for approval.
- Show hidden files in Finder: Cmd + Shift + . to see
.well-known - Firewall: if using your own domain/IP, allow incoming HTTP/HTTPS in System Settings → Network → Firewall
- Keep Terminal (or MAMP + tunnel) running while the node is live
-
localhostwon’t work for registration — the hub needs your public HTTPS URL - The crawler uses your site root for sitemap/homepage by default, even if node files are in a subfolder
Full shared-hosting steps (same files, more detail): litterlayer.com/federation/