this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

migrate to radicle

+462 -36
+2
hosts/box/default.nix
··· 30 30 ../profiles/gpodder 31 31 ../profiles/transmission 32 32 ../profiles/raven 33 + ../profiles/radicle-node 33 34 # ../profiles/postgres_upgrade_script # one-time use 34 35 ]; 35 36 ··· 58 59 "/tank/postgres" # postgres data 59 60 "/tank/media/photos" 60 61 "/tank/media/music" 62 + "/var/lib/radicle" 61 63 ]; 62 64 }; 63 65
+13 -5
hosts/helix/default.nix
··· 1 - { self, profiles, suites, pkgs, ... }: 1 + { 2 + self, 3 + profiles, 4 + suites, 5 + pkgs, 6 + ... 7 + }: 2 8 { 3 9 imports = [ 4 10 ./configuration.nix 5 11 ../profiles/core 6 12 ../profiles/server 7 13 # ../profiles/metrics 8 - ../profiles/gitea 14 + # ../profiles/gitea # Replaced by radicle 15 + ../profiles/radicle-seed 9 16 # ../profiles/woodpecker-server 10 17 ../profiles/rss-bridge 11 18 # ../profiles/mount-mossnet 12 19 ../profiles/freshrss 13 20 ../profiles/microbin 14 21 ../profiles/site 15 - 22 + 16 23 # ../profiles/postgres_upgrade_script 17 24 ]; 18 25 ··· 50 57 services.postgresqlBackup = { 51 58 # TODO needs working wireguard to box 52 59 enable = false; 53 - databases = [ "gitea" "freshrss" ]; # "woodpecker" 60 + databases = [ "freshrss" ]; # gitea removed (now using radicle) 54 61 location = "/mnt/two/postgres"; 55 62 }; 56 63 ··· 58 65 enable = true; 59 66 name = "helix"; 60 67 paths = [ 61 - "/var/lib/gitea" 68 + # "/var/lib/gitea" # Replaced by radicle 69 + "/var/lib/radicle" 62 70 "/var/lib/freshrss" 63 71 # "/var/lib/woodpecker" 64 72 "/var/lib/microbin"
+40 -20
hosts/profiles/dns/default.nix
··· 1 - { config, pkgs, lib, ... }: 1 + { 2 + config, 3 + pkgs, 4 + lib, 5 + ... 6 + }: 2 7 let 3 8 adblockLocalZones = pkgs.stdenv.mkDerivation { 4 9 name = "unbound-zones-adblock"; 5 10 6 - src = (pkgs.fetchFromGitHub { 7 - owner = "StevenBlack"; 8 - repo = "hosts"; 9 - rev = "3.12.21"; 10 - sha256 = "Yzr6PY/zqQE+AHH0J6ioHTsgkikM+dz4aelbGpQJa1s="; 11 - } + "/hosts"); 11 + src = ( 12 + pkgs.fetchFromGitHub { 13 + owner = "StevenBlack"; 14 + repo = "hosts"; 15 + rev = "3.12.21"; 16 + sha256 = "Yzr6PY/zqQE+AHH0J6ioHTsgkikM+dz4aelbGpQJa1s="; 17 + } 18 + + "/hosts" 19 + ); 12 20 13 21 phases = [ "installPhase" ]; 14 22 ··· 40 48 "photos.mossnet.lan" 41 49 "pod.mossnet.lan" 42 50 "mast.mossnet.lan" 51 + "rad.mossnet.lan" 43 52 ]; 44 53 45 - in { 54 + in 55 + { 46 56 services.unbound = { 47 57 enable = true; 48 58 settings = { ··· 53 63 # private-address = "192.168.1.0/24"; 54 64 cache-min-ttl = 0; 55 65 serve-expired = "yes"; 56 - interface = [ "0.0.0.0" "::" ]; 57 - access-control = 58 - [ "127.0.0.0/8 allow" "192.168.1.0/24 allow" "10.0.69.0/24 allow" "::1 allow" "fd7d:587a:4300:1::/64 allow" ]; 66 + interface = [ 67 + "0.0.0.0" 68 + "::" 69 + ]; 70 + access-control = [ 71 + "127.0.0.0/8 allow" 72 + "192.168.1.0/24 allow" 73 + "10.0.69.0/24 allow" 74 + "::1 allow" 75 + "fd7d:587a:4300:1::/64 allow" 76 + ]; 59 77 access-control-view = "10.0.69.0/24 wireguard"; 60 78 # so-reuseport = "yes"; 61 79 tls-upstream = "yes"; ··· 63 81 local-zone = ''"mossnet.lan." redirect''; 64 82 local-data = ''"mossnet.lan. IN A ${mossnet}"''; 65 83 }; 66 - forward-zone = [{ 67 - name = "."; 68 - forward-addr = [ 69 - "45.90.28.0#6939b9.dns.nextdns.io" 70 - "1.1.1.1@853#cloudflare-dns.com" 71 - ]; 72 - # non-tls 73 - # forward-addr = ["45.90.30.49" "45.90.28.49" "1.1.1.1" "8.8.8.8"] 74 - }]; 84 + forward-zone = [ 85 + { 86 + name = "."; 87 + forward-addr = [ 88 + "45.90.28.0#6939b9.dns.nextdns.io" 89 + "1.1.1.1@853#cloudflare-dns.com" 90 + ]; 91 + # non-tls 92 + # forward-addr = ["45.90.30.49" "45.90.28.49" "1.1.1.1" "8.8.8.8"] 93 + } 94 + ]; 75 95 view = { 76 96 name = "wireguard"; 77 97 local-zone = ''"mossnet.lan." redirect'';
+85
hosts/profiles/radicle-node/default.nix
··· 1 + { 2 + self, 3 + config, 4 + pkgs, 5 + ... 6 + }: 7 + let 8 + # Custom radicle-explorer configured for local box node 9 + localExplorer = pkgs.radicle-explorer.withConfig { 10 + preferredSeeds = [ 11 + { 12 + hostname = "rad.mossnet.lan"; 13 + port = 80; 14 + scheme = "http"; 15 + } 16 + ]; 17 + }; 18 + in 19 + { 20 + age.secrets.radicle-box-key.file = "${self}/secrets/radicle-box-key.age"; 21 + age.secrets.radicle-box-key.owner = "radicle"; 22 + 23 + services.radicle = { 24 + enable = true; 25 + privateKeyFile = config.age.secrets.radicle-box-key.path; 26 + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII2QC5AbaTHCRVzGluWgXUlyBNFDxcLiIeViv81f3TYw mossnet.lan"; 27 + 28 + node = { 29 + listenAddress = "0.0.0.0"; # Listen on all interfaces for local LAN access 30 + listenPort = 8776; 31 + openFirewall = true; 32 + }; 33 + 34 + settings = { 35 + node = { 36 + alias = "mossnet.lan"; 37 + connect = [ "z6MkfPhJnbrHbB4FNcub7weT8CRcqFgfJinDfSYjPwK9tSXy@10.0.69.5:8776" ]; 38 + seedingPolicy.default = "block"; 39 + }; 40 + }; 41 + 42 + # HTTP API for local web access 43 + httpd = { 44 + enable = true; 45 + listenAddress = "127.0.0.1"; 46 + listenPort = 8888; 47 + }; 48 + }; 49 + 50 + # Nginx to serve radicle-explorer + proxy API 51 + services.nginx = { 52 + enable = true; 53 + recommendedProxySettings = true; 54 + 55 + virtualHosts."rad.mossnet.lan" = { 56 + root = localExplorer; 57 + 58 + locations."/" = { 59 + tryFiles = "$uri $uri/ /index.html"; 60 + index = "index.html"; 61 + }; 62 + 63 + # Proxy API requests to radicle-httpd 64 + locations."/api" = { 65 + proxyPass = "http://127.0.0.1:8888"; 66 + }; 67 + 68 + # Proxy raw file access to radicle-httpd 69 + locations."/raw" = { 70 + proxyPass = "http://127.0.0.1:8888"; 71 + }; 72 + 73 + # Proxy git protocol requests (rad:xxx) to radicle-httpd 74 + locations."~ ^/rad:" = { 75 + proxyPass = "http://127.0.0.1:8888"; 76 + }; 77 + }; 78 + }; 79 + 80 + # Open firewall for nginx 81 + networking.firewall.allowedTCPPorts = [ 80 ]; 82 + 83 + # rad CLI for interactive use 84 + environment.systemPackages = [ pkgs.radicle-node ]; 85 + }
+85
hosts/profiles/radicle-seed/default.nix
··· 1 + { 2 + self, 3 + config, 4 + pkgs, 5 + lib, 6 + ... 7 + }: 8 + let 9 + # Custom radicle-explorer with our seed as preferred 10 + customExplorer = pkgs.radicle-explorer.withConfig { 11 + preferredSeeds = [ 12 + { 13 + hostname = "git.sealight.xyz"; 14 + port = 443; 15 + scheme = "https"; 16 + } 17 + ]; 18 + }; 19 + in 20 + { 21 + age.secrets.radicle-helix-key.file = "${self}/secrets/radicle-helix-key.age"; 22 + age.secrets.radicle-helix-key.owner = "radicle"; 23 + 24 + services.radicle = { 25 + enable = true; 26 + privateKeyFile = config.age.secrets.radicle-helix-key.path; 27 + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA3x7XH24gEr8xHnt1qKQx38Se2AoXiUnb48/VwfL8/A git.sealight.xyz"; 28 + 29 + node = { 30 + listenAddress = "0.0.0.0"; 31 + listenPort = 8776; 32 + openFirewall = true; 33 + }; 34 + 35 + settings = { 36 + node = { 37 + alias = "git.sealight.xyz"; 38 + externalAddresses = [ "git.sealight.xyz:8776" ]; 39 + connect = [ "z6MkoyrvcRdeGU5PyB2SbHj9mNj3nb5p34rZamkEz64GX1c3@10.0.69.4:8776" ]; 40 + seedingPolicy.default = "block"; 41 + }; 42 + }; 43 + 44 + httpd = { 45 + enable = true; 46 + listenAddress = "127.0.0.1"; 47 + listenPort = 8080; 48 + # Don't use the module's nginx integration - we'll configure it manually 49 + nginx = null; 50 + }; 51 + }; 52 + 53 + # Configure nginx manually for radicle-explorer + httpd API 54 + services.nginx.virtualHosts."git.sealight.xyz" = { 55 + enableACME = true; 56 + forceSSL = true; 57 + 58 + # Serve radicle-explorer static files at root 59 + root = customExplorer; 60 + 61 + locations."/" = { 62 + tryFiles = "$uri $uri/ /index.html"; 63 + index = "index.html"; 64 + }; 65 + 66 + # Proxy API requests to radicle-httpd 67 + locations."/api" = { 68 + proxyPass = "http://127.0.0.1:8080"; 69 + recommendedProxySettings = true; 70 + }; 71 + 72 + # Proxy raw file access to radicle-httpd 73 + locations."/raw" = { 74 + proxyPass = "http://127.0.0.1:8080"; 75 + recommendedProxySettings = true; 76 + }; 77 + 78 + # Proxy git protocol requests (rad:xxx) to radicle-httpd 79 + # These are requests to /:rid/* where rid starts with "rad:" 80 + locations."~ ^/rad:" = { 81 + proxyPass = "http://127.0.0.1:8080"; 82 + recommendedProxySettings = true; 83 + }; 84 + }; 85 + }
+168
scripts/migrate-forgejo-to-radicle.sh
··· 1 + #!/usr/bin/env bash 2 + set -euo pipefail 3 + 4 + # Migration script: Forgejo bare repos -> Radicle 5 + # 6 + # Usage: 7 + # 1. First rsync repos from helix: 8 + # rsync -avz git.sealight.xyz:/var/lib/gitea/repositories/aynish/ /tmp/forgejo-migration/ 9 + # 10 + # 2. Run this script: 11 + # sudo -u radicle ./migrate-forgejo-to-radicle.sh /tmp/forgejo-migration 12 + # 13 + # Or run as root: 14 + # ./migrate-forgejo-to-radicle.sh /tmp/forgejo-migration 15 + 16 + SOURCE_DIR="${1:-/tmp/forgejo-migration}" 17 + WORK_DIR="/var/lib/radicle/migration" 18 + LOG_FILE="/var/lib/radicle/migration.log" 19 + 20 + # Colors 21 + RED='\033[0;31m' 22 + GREEN='\033[0;32m' 23 + YELLOW='\033[1;33m' 24 + NC='\033[0m' 25 + 26 + log() { echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"; } 27 + log_success() { log "${GREEN}✓ $1${NC}"; } 28 + log_warn() { log "${YELLOW}⚠ $1${NC}"; } 29 + log_error() { log "${RED}✗ $1${NC}"; } 30 + 31 + # Use rad directly with proper environment (rad-system can't access files outside sandbox) 32 + export RAD_HOME=/var/lib/radicle 33 + export HOME=/var/lib/radicle 34 + RAD_CMD="rad" 35 + 36 + # Ensure keys are in place (agenix stores them in /run/agenix/) 37 + if [[ -f /run/agenix/radicle-box-key ]] && [[ ! -s /var/lib/radicle/keys/radicle ]]; then 38 + log "Setting up radicle keys..." 39 + cp /run/agenix/radicle-box-key /var/lib/radicle/keys/radicle 40 + chmod 600 /var/lib/radicle/keys/radicle 41 + chown radicle:radicle /var/lib/radicle/keys/radicle 42 + fi 43 + 44 + # Get public key from the config if not present 45 + if [[ ! -s /var/lib/radicle/keys/radicle.pub ]]; then 46 + log "Generating public key..." 47 + ssh-keygen -y -f /var/lib/radicle/keys/radicle > /var/lib/radicle/keys/radicle.pub 2>/dev/null || true 48 + chown radicle:radicle /var/lib/radicle/keys/radicle.pub 49 + fi 50 + 51 + # Check source directory 52 + if [[ ! -d "$SOURCE_DIR" ]]; then 53 + log_error "Source directory not found: $SOURCE_DIR" 54 + echo "" 55 + echo "First rsync repos from helix:" 56 + echo " rsync -avz git.sealight.xyz:/var/lib/gitea/repositories/aynish/ /tmp/forgejo-migration/" 57 + exit 1 58 + fi 59 + 60 + # Create work directory 61 + mkdir -p "$WORK_DIR" 62 + cd "$WORK_DIR" 63 + 64 + log "Starting Forgejo -> Radicle migration" 65 + log "Source: $SOURCE_DIR" 66 + log "Work dir: $WORK_DIR" 67 + log "Using: $RAD_CMD" 68 + 69 + # Count repos 70 + REPOS=$(find "$SOURCE_DIR" -maxdepth 1 -name "*.git" -type d | sort) 71 + TOTAL=$(echo "$REPOS" | grep -c . || echo 0) 72 + 73 + if [[ "$TOTAL" -eq 0 ]]; then 74 + log_error "No .git directories found in $SOURCE_DIR" 75 + exit 1 76 + fi 77 + 78 + log "Found $TOTAL repositories to migrate" 79 + echo "" 80 + 81 + MIGRATED=0 82 + SKIPPED=0 83 + FAILED=0 84 + 85 + for BARE_REPO in $REPOS; do 86 + # Extract repo name (remove .git suffix) 87 + REPO_NAME=$(basename "$BARE_REPO" .git) 88 + 89 + log "Processing: $REPO_NAME" 90 + 91 + CLONE_DIR="$WORK_DIR/$REPO_NAME" 92 + 93 + # Clone bare repo to working directory 94 + if [[ -d "$CLONE_DIR/.git" ]]; then 95 + log " Directory exists, skipping clone" 96 + else 97 + log " Cloning from bare repo..." 98 + if ! git clone --quiet "$BARE_REPO" "$CLONE_DIR" 2>>"$LOG_FILE"; then 99 + log_error " Failed to clone $REPO_NAME" 100 + ((FAILED++)) || true 101 + continue 102 + fi 103 + fi 104 + 105 + cd "$CLONE_DIR" 106 + 107 + # Check if already initialized in Radicle 108 + if $RAD_CMD . >/dev/null 2>&1; then 109 + log_warn " Already initialized in Radicle, skipping" 110 + cd "$WORK_DIR" 111 + ((SKIPPED++)) || true 112 + continue 113 + fi 114 + 115 + # Get current branch 116 + CURRENT_BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo "main") 117 + 118 + # Normalize to main if needed 119 + if [[ "$CURRENT_BRANCH" != "main" ]]; then 120 + log " Normalizing branch: $CURRENT_BRANCH -> main" 121 + git branch -m "$CURRENT_BRANCH" main 2>>"$LOG_FILE" || true 122 + fi 123 + 124 + # Get description from git config if available 125 + DESCRIPTION=$(git config --get gitweb.description 2>/dev/null || echo "Migrated from Forgejo") 126 + 127 + # Truncate description if too long 128 + if [[ ${#DESCRIPTION} -gt 255 ]]; then 129 + DESCRIPTION="${DESCRIPTION:0:252}..." 130 + fi 131 + 132 + # Initialize in Radicle 133 + log " Initializing in Radicle..." 134 + if $RAD_CMD init \ 135 + --name "$REPO_NAME" \ 136 + --description "$DESCRIPTION" \ 137 + --default-branch main \ 138 + --public 2>>"$LOG_FILE"; then 139 + 140 + # Push to radicle 141 + log " Pushing to Radicle..." 142 + if git push rad main 2>>"$LOG_FILE"; then 143 + RID=$($RAD_CMD . 2>/dev/null || echo "unknown") 144 + log_success " Migrated: $REPO_NAME -> $RID" 145 + ((MIGRATED++)) || true 146 + else 147 + log_error " Failed to push $REPO_NAME" 148 + ((FAILED++)) || true 149 + fi 150 + else 151 + log_error " Failed to init $REPO_NAME in Radicle" 152 + ((FAILED++)) || true 153 + fi 154 + 155 + cd "$WORK_DIR" 156 + done 157 + 158 + echo "" 159 + log "========================================" 160 + log "Migration Summary:" 161 + log " Total repos: $TOTAL" 162 + log " Migrated: $MIGRATED" 163 + log " Skipped: $SKIPPED" 164 + log " Failed: $FAILED" 165 + log "========================================" 166 + echo "" 167 + log "Verify with: $RAD_CMD ls" 168 + log "Configure helix to follow: rad-system follow <box-nid> --alias mossnet"
secrets/radicle-box-key.age

This is a binary file and will not be displayed.

+9
secrets/radicle-helix-key.age
··· 1 + age-encryption.org/v1 2 + -> ssh-ed25519 kgCrKA WzvIX43OcJw/qxPgTw3iUjorQ0ahFHYZEmnghnUz/xc 3 + HtNx7XqWFZDNpjNiquxfRrnP/TcXxoPn6mMB0BMjlJw 4 + -> ssh-ed25519 6DaCrw dZ9etYRaGuAO0gcA3Krdgvcg9vkwctAtJzKevgjE3wc 5 + gbWQHzO//bGp3Jl513GIgzaM4FzJSiA5thOSWWsx7ik 6 + --- QeO3vdOBbisSZaBECB1Wa603H6P7lXDJwxerJ8gH4+M 7 + �lG��X��.�����$lp^^ �0�zK8�8�Qu�Q���q;Y���85��RM�4���I:g��q����pܺ���,O�dPk�R��rq�U��M��!��=Eu�2 �[_�!%CE�� 8 + ��"��o� 3w��l" :T�6���T��[[Pn��q�B� 7'�F��8���:6E�ͳ�ʽ\� �#�1�Ğ��K�j�.�Ь��)V���Bu�N �"��S,���^��Dŝ&�Ʃ���h�%*�g����v�N^�-��2P��B��b�'? �L�jF,�-�b��:�,�x#�į� UY�_�Qp���+�j�!�U����;�A��ј��r��5�ӏ0��A�|<��=j�ߏ�s��q;b��!BW'ݴ�8�A�s�#�= ��i��`|�N٬�K�o̰H���)��ް 9 + �?�"�� 7�p��W�����ҏ
+60 -11
secrets/secrets.nix
··· 7 7 helix = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAKrL6IDHNnHmxi0q9nzu87NOyidPm3HpE7klU368lEf root@helix"; 8 8 helix2 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK2G81z1E51ioJQGLHnTJEjgSdBqLM6mb72Z+0atE6Bf root@helix"; 9 9 work = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHOnfDvR2D2nGnC+DZYDUXiokzz+eLfZwkp+O8WjWutp anishlakhwara@Anishs-MacBook-Pro.local"; 10 - curve = [ system user ]; 11 - allUserKeys = [ system user mossnet ]; 12 - systemOnly = [ system mossnet lituus helix ]; 10 + curve = [ 11 + system 12 + user 13 + ]; 14 + allUserKeys = [ 15 + system 16 + user 17 + mossnet 18 + ]; 19 + systemOnly = [ 20 + system 21 + mossnet 22 + lituus 23 + helix 24 + ]; 13 25 in 14 26 { 15 27 "taskwarrior-private.age".publicKeys = curve; ··· 20 32 "borg-password.age".publicKeys = systemOnly; 21 33 "borg-key.age".publicKeys = systemOnly; 22 34 23 - "helix-wg.age".publicKeys = [ helix2 helix ]; 24 - "freshrss-dbpass.age".publicKeys = [ helix2 helix ]; 25 - "woodpecker-server-secrets.age".publicKeys = [ helix2 helix ]; 26 - "gitea-dbpass.age".publicKeys = [ helix helix2 ]; 35 + "helix-wg.age".publicKeys = [ 36 + helix2 37 + helix 38 + ]; 39 + "freshrss-dbpass.age".publicKeys = [ 40 + helix2 41 + helix 42 + ]; 43 + "woodpecker-server-secrets.age".publicKeys = [ 44 + helix2 45 + helix 46 + ]; 47 + "gitea-dbpass.age".publicKeys = [ 48 + helix 49 + helix2 50 + ]; 27 51 28 52 "synapse-config.age".publicKeys = [ lituus ]; 29 53 "synapse-database-password.age".publicKeys = [ lituus ]; ··· 31 55 "telegram-matrix-env.age".publicKeys = [ lituus ]; 32 56 33 57 "wallabag.age".publicKeys = [ mossnet ]; 34 - "woodpecker-agent-secret.age".publicKeys = [ mossnet helix helix2 ]; 58 + "woodpecker-agent-secret.age".publicKeys = [ 59 + mossnet 60 + helix 61 + helix2 62 + ]; 35 63 "box-wg.age".publicKeys = [ mossnet ]; 36 64 "wallabag-password.age".publicKeys = [ mossnet ]; 37 65 "wallabag-secret.age".publicKeys = [ mossnet ]; 38 66 39 - "work-wg.age".publicKeys = [ work user system ]; 40 - "github-token.age".publicKeys = [ work user system mossnet ]; 41 - "anthropicToken.age".publicKeys = [ work user system mossnet ]; 67 + "work-wg.age".publicKeys = [ 68 + work 69 + user 70 + system 71 + ]; 72 + "github-token.age".publicKeys = [ 73 + work 74 + user 75 + system 76 + mossnet 77 + ]; 78 + "anthropicToken.age".publicKeys = [ 79 + work 80 + user 81 + system 82 + mossnet 83 + ]; 84 + 85 + # Radicle node keys 86 + "radicle-box-key.age".publicKeys = [ mossnet ]; 87 + "radicle-helix-key.age".publicKeys = [ 88 + helix 89 + helix2 90 + ]; 42 91 }