feat(host): atproto-likes web UI at atproto.commoninternet.net
Imports the notplants-atproto module: Docker daemon (this host had none), a systemd unit running the project's docker-compose stack, and an nginx vhost proxying to it on 127.0.0.1:8731 with ACME and websocket support. Opens 80/443 publicly. Until now only 22 was open and everything else was tailnet-only, so this is a real change in exposure — nginx is now reachable from the internet. The existing oc.commoninternet.net vhost is untouched and stays bound to the tailscale IP. nix/atproto-likes.nix is a COPY; the canonical file lives in the project repo at /srv/project-orchestrator/projects/notplants-atproto/nix/. Pure evaluation forbids importing an absolute path outside the flake tree, so it has to be duplicated here — and a new file must be git-added or nix silently ignores it. ACME currently FAILS: *.commoninternet.net is a wildcard pointing at 143.244.213.108, so the HTTP-01 challenge is answered by that host (500). nginx serves a self-signed placeholder and starts fine. Fix is an explicit A record atproto.commoninternet.net -> 168.119.126.100, then `systemctl start acme-atproto.commoninternet.net.service`. Applied with nixos-rebuild switch; container healthy, TLS proxy and wss verified end to end. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SmEK2voMnBa23495aLk1Ce
This commit is contained in:
co-authored by
Claude Opus 5
parent
56d09016e5
commit
ff054e790c
@@ -0,0 +1,89 @@
|
||||
# atproto-likes — the "most-liked accounts" web UI, run as a docker-compose stack
|
||||
# behind the host's nginx.
|
||||
#
|
||||
# ⚠️ COPY. Canonical source:
|
||||
# /srv/project-orchestrator/projects/notplants-atproto/nix/atproto-likes.nix
|
||||
# A flake cannot import an absolute path outside its own tree under pure
|
||||
# evaluation, so the module is copied here. Re-copy after editing the original.
|
||||
#
|
||||
# Import this from the host configuration:
|
||||
# imports = [ /srv/project-orchestrator/projects/notplants-atproto/nix/atproto-likes.nix ];
|
||||
#
|
||||
# What it sets up:
|
||||
# * the Docker daemon (this host had none before)
|
||||
# * a systemd unit that builds and runs docker-compose.yml from the project checkout
|
||||
# * an nginx vhost for atproto.commoninternet.net with a Let's Encrypt cert,
|
||||
# proxying to the container on 127.0.0.1:8731
|
||||
# * ports 80/443 open (they were closed — only 22 was public)
|
||||
#
|
||||
# DNS: *.commoninternet.net is a wildcard pointing at 143.244.213.108, which is NOT
|
||||
# this host. Until an explicit A record
|
||||
# atproto.commoninternet.net -> 168.119.126.100
|
||||
# overrides that wildcard, ACME's HTTP-01 challenge cannot succeed and the domain
|
||||
# keeps resolving elsewhere. nginx still starts in the meantime — NixOS installs a
|
||||
# self-signed placeholder cert — so nothing else on the host is affected.
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
projectDir = "/srv/project-orchestrator/projects/notplants-atproto";
|
||||
domain = "atproto.commoninternet.net";
|
||||
hostPort = 8731; # must match the ports: mapping in docker-compose.yml
|
||||
compose = "${pkgs.docker-compose}/bin/docker-compose";
|
||||
in
|
||||
{
|
||||
virtualisation.docker = {
|
||||
enable = true;
|
||||
# Reclaim dangling images from repeated `--build` runs.
|
||||
autoPrune = { enable = true; dates = "weekly"; };
|
||||
};
|
||||
|
||||
# Build + run the compose stack. Type=oneshot with RemainAfterExit: compose
|
||||
# detaches, and the containers' own restart policy keeps them alive.
|
||||
systemd.services.atproto-likes = {
|
||||
description = "atproto-likes — most-liked-accounts web UI (docker compose)";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "docker.service" "docker.socket" "network-online.target" ];
|
||||
requires = [ "docker.service" ];
|
||||
wants = [ "network-online.target" ];
|
||||
path = [ pkgs.docker pkgs.docker-compose ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
WorkingDirectory = projectDir;
|
||||
# A cold `--build` pulls python:3.12-slim and installs pip deps.
|
||||
TimeoutStartSec = "1800";
|
||||
ExecStart = "${compose} up -d --build --remove-orphans";
|
||||
ExecStop = "${compose} down";
|
||||
Restart = "on-failure";
|
||||
RestartSec = "30s";
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedProxySettings = true;
|
||||
virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString hostPort}";
|
||||
# The loading page streams scan progress over a websocket.
|
||||
proxyWebsockets = true;
|
||||
# A cold scan can run for minutes with the socket open; the default 60s
|
||||
# proxy read timeout would cut the loading page off mid-flower.
|
||||
extraConfig = ''
|
||||
proxy_read_timeout 1800s;
|
||||
proxy_send_timeout 1800s;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
defaults.email = "mfowler.email@protonmail.com";
|
||||
};
|
||||
|
||||
# Public HTTP/HTTPS. Before this, only 22 was open on the public interface.
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
}
|
||||
@@ -9,6 +9,13 @@
|
||||
{
|
||||
# hardware.nix is the nixos-infect generated hardware-configuration.nix (see README Stage 2a).
|
||||
|
||||
# atproto-likes — the notplants-atproto "most-liked accounts" web UI, served at
|
||||
# atproto.commoninternet.net. Brings in Docker + a compose stack + an nginx vhost
|
||||
# with ACME, and opens 80/443 (previously only 22 was public). Canonical source of
|
||||
# the module is the project repo; ../atproto-likes.nix is a copy kept in this tree
|
||||
# because pure evaluation cannot import a path outside the flake.
|
||||
imports = [ ../../atproto-likes.nix ];
|
||||
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings.PermitRootLogin = "yes";
|
||||
|
||||
Reference in New Issue
Block a user