Everything learned about serving static files on the domedog.pro server • 06.03.2026
| Detail | Value |
|---|---|
| Server | domedog.pro |
| OS user | clawdie |
| Web server | nginx (system service, runs as www-data) |
| Web root | /home/clawdie/htdocs/domedog.pro/ |
| nginx config | /etc/nginx/sites-enabled/domedog.pro.conf |
| SSL | Let's Encrypt via /etc/letsencrypt/live/domedog.pro/ |
| HTTP→HTTPS | 301 redirect (port 80 → 443) |
server {
listen 80;
listen [::]:80;
server_name domedog.pro;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name domedog.pro;
ssl_certificate /etc/letsencrypt/live/domedog.pro/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domedog.pro/privkey.pem;
root /home/clawdie/htdocs/domedog.pro;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
When a new HTML file was created by Clawdie (writing as user clawdie), it got a 404 in the browser even though the file existed on disk.
/home/clawdie/htdocs/domedog.pro/page.html but https://domedog.pro/page.html returns 404.
Step 1 — Check the umask:
$ umask
0007
Umask 0007 means: remove write+exec from group, remove all permissions from others. New files get mode 660 (rw-rw----), new directories get 770 (rwxrwx---).
Step 2 — Check who nginx runs as:
$ id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Step 3 — Check file permissions:
$ ls -la /home/clawdie/htdocs/domedog.pro/page.html
-rw-rw---- 1 clawdie clawdie 23916 Mar 6 09:34 page.html
# ^^^ 660: owner+group can read, others (www-data) CANNOT
Conclusion: nginx (www-data) is not in the clawdie group, so it gets "others" permissions — which is nothing. nginx returns 404 (or 403) because it cannot read the file.
# Add www-data to the clawdie group
sudo usermod -a -G clawdie www-data
# Reload nginx to pick up the new group membership
sudo systemctl reload nginx
After this:
www-data is now in group clawdie660 and group clawdie are readable by nginxchmod individual files ever againclawdie user will automatically inherit group clawdiewww-data read access to all files on the system that have group clawdie and mode g+r. Since our umask is 0007, that means any file created by the clawdie user anywhere. Keep sensitive files in credentials/ with mode 600 (owner-only) to exclude them.
Work through these in order:
ls -la /home/clawdie/htdocs/domedog.pro/your-file.htmlsudo nginx -T | grep -A20 "domedog"
# Look for: root /home/clawdie/htdocs/domedog.pro;ls -la /home/clawdie/htdocs/domedog.pro/your-file.html
# Need at least: -rw-r--r-- (644) OR -rw-rw---- (660) with www-data in clawdie group
stat -c "%a %G %n" /home/clawdie/htdocs/domedog.pro/your-file.html
# Should show: 644 clawdie ... OR 660 clawdie ... (with www-data in group)ls -ld /home/clawdie /home/clawdie/htdocs /home/clawdie/htdocs/domedog.pro
# All dirs need at least o+x (execute/traverse) or www-data in the groupsudo tail -20 /var/log/nginx/error.log
# "Permission denied" = file exists, can't read (permissions issue)
# "No such file or directory" = wrong path or file doesn't existsudo nginx -t # test config syntax first
sudo systemctl reload nginx # apply without dropping connectionsIf you ever need to fix a single file quickly before the group membership kicks in (nginx requires restart/reload to pick up new group memberships for running worker processes):
# Make a single file world-readable
chmod 644 /home/clawdie/htdocs/domedog.pro/your-file.html
# Make all files in webroot world-readable at once
chmod 644 /home/clawdie/htdocs/domedog.pro/*.html
The server uses umask 0007 (set in ~/.bashrc). This is intentional — it makes all files private by default, only accessible to owner and group members.
| What gets created | Mode | Readable by |
|---|---|---|
| File (default) | 660 (rw-rw----) | owner + clawdie group members |
| Directory (default) | 770 (rwxrwx---) | owner + clawdie group members |
| Sensitive file (manual) | 600 (rw-------) | owner only |
| Public web file (after fix) | 660 (rw-rw----) | owner + clawdie group (now includes www-data) |
.env, credentials/, session files, etc. The current approach (tight umask + group membership for nginx) is the right balance of security and convenience.
| URL | File | Description |
|---|---|---|
/ | index.html | Clawdie PRD — product requirements document |
/stripe-agents-plan.html | stripe-agents-plan.html | Stripe Agents implementation plan |
/clawdie-openclaw-transition-plan.html | clawdie-openclaw-transition-plan.html | OpenClaw skills system deep dive |
/clawdie-and-nginx.html | clawdie-and-nginx.html | This document |
# Test config syntax (always do this before reload)
sudo nginx -t
# Dump full merged config (great for debugging)
sudo nginx -T
# Reload (apply config changes, no downtime)
sudo systemctl reload nginx
# Restart (full restart, brief downtime)
sudo systemctl restart nginx
# Check status
sudo systemctl status nginx
# Watch error log live
sudo tail -f /var/log/nginx/error.log
# Watch access log live
sudo tail -f /var/log/nginx/access.log
# Check what groups www-data is in (verify the fix)
groups www-data
# Should show: www-data : www-data clawdie
SSL certificates are managed by Certbot and stored at /etc/letsencrypt/live/domedog.pro/. They auto-renew via a system timer. To check expiry:
# Check certificate expiry
sudo certbot certificates
# Test renewal (dry run, no changes)
sudo certbot renew --dry-run
# Force renew now
sudo certbot renew --force-renewal
301 in nginx. All traffic is encrypted. There is no plain HTTP serving of content.