From b8402a9049c941bd32da3efafbe7878f61120a85 Mon Sep 17 00:00:00 2001 From: Ellie <6687206+wizzeh@users.noreply.github.com> Date: Sun, 15 Feb 2026 14:57:00 -0800 Subject: [PATCH] Initial commit Co-Authored-By: Claude Opus 4.6 --- .gitignore | 1 + .sops.yaml | 5 + common.nix | 81 ++++++ data/service-directory/images/3d-software.png | Bin 0 -> 612 bytes data/service-directory/images/_icons.png | Bin 0 -> 17523 bytes data/service-directory/images/angel01.gif | Bin 0 -> 5822 bytes data/service-directory/images/angel02.gif | Bin 0 -> 5647 bytes data/service-directory/images/book-01.png | Bin 0 -> 527 bytes data/service-directory/images/book-02.png | Bin 0 -> 433 bytes data/service-directory/images/book-03.png | Bin 0 -> 606 bytes data/service-directory/images/capcut.png | Bin 0 -> 654 bytes data/service-directory/images/chat.png | Bin 0 -> 389 bytes data/service-directory/images/cursor-01.png | Bin 0 -> 268 bytes data/service-directory/images/cursor-02.png | Bin 0 -> 260 bytes data/service-directory/images/cursor-03.png | Bin 0 -> 474 bytes .../images/cursor-04-cuttledreams.png | Bin 0 -> 547 bytes data/service-directory/images/cursor-05.png | Bin 0 -> 390 bytes data/service-directory/images/cursor-06.png | Bin 0 -> 598 bytes data/service-directory/images/cursor-07.png | Bin 0 -> 402 bytes data/service-directory/images/cursor-08.png | Bin 0 -> 393 bytes data/service-directory/images/discord.png | Bin 0 -> 638 bytes data/service-directory/images/disk drive.png | Bin 0 -> 780 bytes data/service-directory/images/downloads.png | Bin 0 -> 579 bytes data/service-directory/images/drive-01.png | Bin 0 -> 380 bytes data/service-directory/images/drive-02.png | Bin 0 -> 486 bytes data/service-directory/images/eyedrop.png | Bin 0 -> 637 bytes data/service-directory/images/flower.png | Bin 0 -> 844 bytes data/service-directory/images/folder-01.png | Bin 0 -> 415 bytes data/service-directory/images/folder-02.png | Bin 0 -> 535 bytes data/service-directory/images/folder-03.png | Bin 0 -> 250 bytes data/service-directory/images/folder-04.png | Bin 0 -> 275 bytes data/service-directory/images/folder-05.png | Bin 0 -> 342 bytes data/service-directory/images/folder-06.png | Bin 0 -> 265 bytes data/service-directory/images/folder-07.png | Bin 0 -> 321 bytes data/service-directory/images/folder-08.png | Bin 0 -> 334 bytes .../images/folder-too many.png | Bin 0 -> 401 bytes data/service-directory/images/games-01.png | Bin 0 -> 696 bytes data/service-directory/images/games-02.png | Bin 0 -> 507 bytes data/service-directory/images/games-03.png | Bin 0 -> 543 bytes data/service-directory/images/illustrator.png | Bin 0 -> 685 bytes data/service-directory/images/indesign.png | Bin 0 -> 609 bytes data/service-directory/images/internet.png | Bin 0 -> 855 bytes data/service-directory/images/juice.png | Bin 0 -> 809 bytes data/service-directory/images/music-01.png | Bin 0 -> 695 bytes data/service-directory/images/music-02.png | Bin 0 -> 676 bytes data/service-directory/images/my puter.png | Bin 0 -> 606 bytes data/service-directory/images/notepad-01.png | Bin 0 -> 466 bytes data/service-directory/images/notepad-02.png | Bin 0 -> 529 bytes data/service-directory/images/onedrive.png | Bin 0 -> 677 bytes .../images/photo-software.png | Bin 0 -> 652 bytes data/service-directory/images/photoshop.png | Bin 0 -> 676 bytes .../images/reference-software.png | Bin 0 -> 798 bytes .../images/roesbudtrelbg.gif | Bin 0 -> 1187 bytes data/service-directory/images/speaker.png | Bin 0 -> 640 bytes data/service-directory/images/telegram.png | Bin 0 -> 506 bytes data/service-directory/images/torrent.png | Bin 0 -> 805 bytes .../images/trash bin-full.png | Bin 0 -> 568 bytes data/service-directory/images/trash bin.png | Bin 0 -> 487 bytes .../service-directory/images/vpn-software.png | Bin 0 -> 726 bytes data/service-directory/images/whatsapp.png | Bin 0 -> 637 bytes data/service-directory/index.html | 48 ++++ data/service-directory/style.css | 60 +++++ flake.lock | 251 ++++++++++++++++++ flake.nix | 90 +++++++ hosts/homeserver/configuration.nix | 70 +++++ hosts/homeserver/hardware-configuration.nix | 25 ++ hosts/homeserver/setup.nix | 91 +++++++ hosts/vps/configuration.nix | 7 + hosts/vps/disko-config.nix | 39 +++ hosts/vps/hardware-configuration.nix | 8 + services/akkoma.nix | 103 +++++++ services/coturn.nix | 72 +++++ services/ergo.nix | 113 ++++++++ services/matrix.nix | 33 +++ services/secrets/coturn_home.yaml | 17 ++ services/secrets/coturn_vps.yaml | 17 ++ services/secrets/ergo.yaml | 17 ++ services/secrets/wireguard_home.yaml | 17 ++ services/secrets/wireguard_vps.yaml | 17 ++ services/website.nix | 31 +++ services/wireguard-inner.nix | 24 ++ services/wireguard-outer.nix | 108 ++++++++ 82 files changed, 1345 insertions(+) create mode 100644 .gitignore create mode 100644 .sops.yaml create mode 100644 common.nix create mode 100644 data/service-directory/images/3d-software.png create mode 100644 data/service-directory/images/_icons.png create mode 100644 data/service-directory/images/angel01.gif create mode 100644 data/service-directory/images/angel02.gif create mode 100644 data/service-directory/images/book-01.png create mode 100644 data/service-directory/images/book-02.png create mode 100644 data/service-directory/images/book-03.png create mode 100644 data/service-directory/images/capcut.png create mode 100644 data/service-directory/images/chat.png create mode 100644 data/service-directory/images/cursor-01.png create mode 100644 data/service-directory/images/cursor-02.png create mode 100644 data/service-directory/images/cursor-03.png create mode 100644 data/service-directory/images/cursor-04-cuttledreams.png create mode 100644 data/service-directory/images/cursor-05.png create mode 100644 data/service-directory/images/cursor-06.png create mode 100644 data/service-directory/images/cursor-07.png create mode 100644 data/service-directory/images/cursor-08.png create mode 100644 data/service-directory/images/discord.png create mode 100644 data/service-directory/images/disk drive.png create mode 100644 data/service-directory/images/downloads.png create mode 100644 data/service-directory/images/drive-01.png create mode 100644 data/service-directory/images/drive-02.png create mode 100644 data/service-directory/images/eyedrop.png create mode 100644 data/service-directory/images/flower.png create mode 100644 data/service-directory/images/folder-01.png create mode 100644 data/service-directory/images/folder-02.png create mode 100644 data/service-directory/images/folder-03.png create mode 100644 data/service-directory/images/folder-04.png create mode 100644 data/service-directory/images/folder-05.png create mode 100644 data/service-directory/images/folder-06.png create mode 100644 data/service-directory/images/folder-07.png create mode 100644 data/service-directory/images/folder-08.png create mode 100644 data/service-directory/images/folder-too many.png create mode 100644 data/service-directory/images/games-01.png create mode 100644 data/service-directory/images/games-02.png create mode 100644 data/service-directory/images/games-03.png create mode 100644 data/service-directory/images/illustrator.png create mode 100644 data/service-directory/images/indesign.png create mode 100644 data/service-directory/images/internet.png create mode 100644 data/service-directory/images/juice.png create mode 100644 data/service-directory/images/music-01.png create mode 100644 data/service-directory/images/music-02.png create mode 100644 data/service-directory/images/my puter.png create mode 100644 data/service-directory/images/notepad-01.png create mode 100644 data/service-directory/images/notepad-02.png create mode 100644 data/service-directory/images/onedrive.png create mode 100644 data/service-directory/images/photo-software.png create mode 100644 data/service-directory/images/photoshop.png create mode 100644 data/service-directory/images/reference-software.png create mode 100644 data/service-directory/images/roesbudtrelbg.gif create mode 100644 data/service-directory/images/speaker.png create mode 100644 data/service-directory/images/telegram.png create mode 100644 data/service-directory/images/torrent.png create mode 100644 data/service-directory/images/trash bin-full.png create mode 100644 data/service-directory/images/trash bin.png create mode 100644 data/service-directory/images/vpn-software.png create mode 100644 data/service-directory/images/whatsapp.png create mode 100644 data/service-directory/index.html create mode 100644 data/service-directory/style.css create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 hosts/homeserver/configuration.nix create mode 100644 hosts/homeserver/hardware-configuration.nix create mode 100644 hosts/homeserver/setup.nix create mode 100644 hosts/vps/configuration.nix create mode 100644 hosts/vps/disko-config.nix create mode 100644 hosts/vps/hardware-configuration.nix create mode 100644 services/akkoma.nix create mode 100644 services/coturn.nix create mode 100644 services/ergo.nix create mode 100644 services/matrix.nix create mode 100644 services/secrets/coturn_home.yaml create mode 100644 services/secrets/coturn_vps.yaml create mode 100644 services/secrets/ergo.yaml create mode 100644 services/secrets/wireguard_home.yaml create mode 100644 services/secrets/wireguard_vps.yaml create mode 100644 services/website.nix create mode 100644 services/wireguard-inner.nix create mode 100644 services/wireguard-outer.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..77f12ae --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +docs/ diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..46b26f7 --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,5 @@ +creation_rules: + - path_regex: .*_vps\.yaml$ + age: age1856wmagg3dz4j07alwqnn6d75655t6wcs8glklyjyezhu5p875fq9sez4p + - path_regex: .*\.yaml$ + age: age126v48dgev6pu3uhe7dtpdhax2yes2ff9u42ke2k2h97e90z8d4psedau7u diff --git a/common.nix b/common.nix new file mode 100644 index 0000000..98b8800 --- /dev/null +++ b/common.nix @@ -0,0 +1,81 @@ +{ lib, ... }: + +{ + nix.gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 7d"; + }; + + time.timeZone = "America/Vancouver"; + + i18n.defaultLocale = "en_US.UTF-8"; + + nix.settings.experimental-features = "nix-command flakes"; + nix.settings.trusted-public-keys = lib.mkAfter [ + "local.yesod.ellie:3cAK/At9uVQq5kNrZco1cuthpgoPy7JfEvd+sBs80fk=" + ]; + + networking.useDHCP = true; + + services.openssh = { + enable = true; + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = "no"; + AllowUsers = [ "ellie" ]; + }; + }; + + services.fail2ban = { + enable = true; + maxretry = 5; + bantime = "1h"; + bantime-increment.enable = true; + jails = { + sshd.settings = { + enabled = true; + maxretry = 3; + }; + nginx-botsearch.settings = { + enabled = true; + filter = "nginx-botsearch"; + backend = "systemd"; + maxretry = 2; + }; + nginx-http-auth.settings = { + enabled = true; + filter = "nginx-http-auth"; + backend = "systemd"; + }; + nginx-bad-request.settings = { + enabled = true; + filter = "nginx-bad-request"; + backend = "systemd"; + }; + }; + }; + + users.mutableUsers = true; + security.sudo.wheelNeedsPassword = true; + + users.users.ellie = { + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOv7i4ChPUm+DmELG6uRx0co4quhQ+h7QB4fgcxcC3qx contact@elliehigh.com" + ]; + + isNormalUser = true; + description = "Ellie"; + extraGroups = [ "wheel" ]; + initialPassword = "install"; + }; + + system.autoUpgrade = { + enable = true; + allowReboot = true; + dates = "04:00"; + }; + + system.stateVersion = "25.05"; +} diff --git a/data/service-directory/images/3d-software.png b/data/service-directory/images/3d-software.png new file mode 100644 index 0000000000000000000000000000000000000000..de5eff8a36440f52e65af7f293f36e009e738cf0 GIT binary patch literal 612 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 P7#KWV{an^LB{Ts5?x{#} literal 0 HcmV?d00001 diff --git a/data/service-directory/images/angel01.gif b/data/service-directory/images/angel01.gif new file mode 100644 index 0000000000000000000000000000000000000000..3ba7911c00dbabc5458c1916ad306703578b09ee GIT binary patch literal 5822 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 aP2C4ybh`)ja85KiF{5X7M++k(gEau3Yt&Hy literal 0 HcmV?d00001 diff --git a/data/service-directory/images/book-01.png b/data/service-directory/images/book-01.png new file mode 100644 index 0000000000000000000000000000000000000000..d55a56c5a8ff50756c17aa1df114e1b59dc5f7f9 GIT binary patch literal 527 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U_9yR z;usRq`Zj!jHj|;qKb_WKE-{vk&f90deNpk>LH*@5Cq>;u2X$q4S={vd%kAR0#x-F1 zqmus(i(mW7-mz_In!Hz2_D$>Ox+g+sw|ei_+_`5@&CgG9pZI+o2K=f zS6^}ce7bzy+z$Rco-4OkAKADv)UQ;JNj36-@+`J>OpA8UiAr7bTT*}_z1*?r>o>0a zpFwNx9%OL|30T$;X^>&S=-M0*#<)3QLr4mXNAHDmCl25B{i9@)BF5~vnol{#Jf}SH4@@&i={nvrQQo7#KWV{an^LB{Ts5NFU_+ literal 0 HcmV?d00001 diff --git a/data/service-directory/images/book-02.png b/data/service-directory/images/book-02.png new file mode 100644 index 0000000000000000000000000000000000000000..f9258195c06ace62036d3b86b28de3c98199b60c GIT binary patch literal 433 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V9fS( zaSVxQeLGdr=dgoF+kQc(%{nV*9B5FO>2Q|s3XclM2bL?ZtkgJ8o)Pg$^x$A>nmO}^ zlSjaV0}B$$vXVHNc=A+OmUX?lIBj>_@wP{G#e1K<|9x-wzTM2q%8UQ63kg~rT(HN} zac$oG&;7qe4wMA_xOw-O%Y*98>I-+8G0NLzq`bT-DR%#!yBuRxSzFoCQwH-7zxw9- z=SI8%XT|w*3@s1-ePZ@eZDd{~bWLG=B$Tm}XP22WQ%mvv4FO#p4az&HQ^ literal 0 HcmV?d00001 diff --git a/data/service-directory/images/book-03.png b/data/service-directory/images/book-03.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f22947b552112d89088e99c1e1789e6e9d27e7 GIT binary patch literal 606 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V3P23 zaSVxQy*ka_v`r>8(D!nbN+dJwikY>lVxmh4E^!&YLUi=w-=Sn`FswvUiVWo{Cn+CZO)SC`KFVd)n_(@ZQuKK zsr!RNv!7Zpw6K-e+cWU2IK-InYprWt=mY6v%legl99a0dv?Rsi&OX@?e4|xx?q{xB z(;f5+0*yrOY|)xCP20(KskQVmwJddpB-_u74K15lIks_po$_wSWb@UZ=VW~Q5yUa^ zWz&N^#VSsTi6ieU-oF~ouwYzr`olLZQmGnOZd?4xes15pDmJ!cq0|8 zcyZ+c#mx`P7f<&2@!*shkMfpXZ=1VwURX0-UiDz7?c?6}=kq)}y8I$~&e&YZZS6n9P?sxgI}sH@R_Uc}+RvuACEL7EhZL=5oA~ z>%P*)|Fcv?s{Ec)FiXs`;Kt@n4=+95vHil)Bf>kYC-!Yk6p;D5hd1=Wi{-qb4{CiI z-ZG2G*k5E%DM(~m7J5*i`0T7nuPr>pS=!g|Z{YWP6{vN2<$?b$H4IP9ULF#!ieALP Pz`)??>gTe~DWM4fS`ZK5 literal 0 HcmV?d00001 diff --git a/data/service-directory/images/capcut.png b/data/service-directory/images/capcut.png new file mode 100644 index 0000000000000000000000000000000000000000..7cf263864c68017d98a5422873a71c50f5baa8d1 GIT binary patch literal 654 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>VDj*E zaSVxQeLLMSLn=_>czw9jqTmAyw+VCzYzUT-SvT9;eS2B)3LB@BH(ht#2#m?+jJ?IO zvAwlyv%rZdhS9Qp0n6n$xSZBHAJ8n_#rIWq`scY)>z%xRwLiA_x&Qm#_q+f9|LwQq z^@T+`V!H~$W3#vF>Rw`O(Yv$OuYBp&$$xFPS;h9P*Wc0`%CAspqV@UJKk1+{-6@}| z7W-)$f7nsyV%JcA_|v(mvrOhZ^}5qt)v!3wQpo%hV@PDLH0QD2BSClUqZ)5)aLu{F zRT~!iU_bXiJ#miM9iO5^BBt4&VbxMxwIhzTMemOL+2;&%gpZ#nyZiVx_fof>igUH! zOWT9e7M#)IStvT;;Q7waYkx2@95*w3v~#A{i3h9JEP0iDSnOoY+?0L$=5V*@-KqOL z;qIf(@TlWvp6S{?-@Z>fXV76Vy=B*e`!*_b*FLzRHhcN>FRNJP>i!-2-7m~gXIHVU z0NnFJpB`|pe4-mJ#6mrpy0S(}UfJT2v-Y0U88?TRxy4F4Mb|Gn%| zLpbB=+)TISt3&qR5fS6gyO$GjgS}~$`6J8lEXP%GMNM-JQm?1|I`Hk_m&&P`8YK@; zmA|<0toK2pIoN&kEL$kQU*D|Ss9N~n#f@>dLQ?}~nZm)P`s?-qjc5+Zdi^lE#x6Rs< zepYFO|Kw`2Rn)Oy%s-zU;JEI{{=cpwsR5oYzp|G}UEh9iPk43t2kxYA;f6)^8~!pd PFfe$!`njxgN@xNAmDM*P literal 0 HcmV?d00001 diff --git a/data/service-directory/images/chat.png b/data/service-directory/images/chat.png new file mode 100644 index 0000000000000000000000000000000000000000..991c92f450bb6ae82c735e455c37c22a9fa14556 GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V6^vi zaSVxQeLK~b>yU#$tGbYZxPVSj^s)^bzVJQb3|e`kTENj~dqqP+YUX64rF&Z!2%KQt z(tS0n=eP09yDM7P$E1C)wcfpl@yF}aMK0YB6?A49Bx_cGE_Qvk{OplkKkvmlSxbmr zG_7o`V197xr}%D`nH7;-3=9TQPfrT+V|5lj_F+5{ad%vDlpw!{py^x9430Z4cKWw`3<3n_LjC{k=Gc&*S zA3bwJE}^z#tH2??kk7N$Bt*PWm{QNcqo(XVQ#e+*-FX7Tipd*oe$Er9t7TYsYw|{; zpB5~V3?efd&NAQJ@5Fq9M~ZjRrV!)%EGJeln_Uv%WtetpBF}?V!!u3BzY=n0EM(ZR ub8Cyv%2v&+Q!=aU^wRK z;usRqn(SlZ{pY-c+Kl=vJLR2Ki4Codjg5)-F3nHLOuN4MxBcVaid`}XnUeS1ndLR< zSc|;5q=>|{z$9~K5D-49##73^L0};ppHST$nFw|blSRiYmvT->VGlSRl;RL1RS_V6 zbi%<*_p+Ui8<{g0JIWjm_0Q(v>OH+ejy2*k!xVA$vB z;usRqn(SlZ{pY-c+Kl=vJLR2Ki4Codjg5)7;^a4(Z0^4M*Z%Qu#V(nHOvwd%BD^OZ zn;spkxlx>N#)_m<0c8x_f>{q5q7M3PW0ul-9r$C4n!_Yn2VL)pjGmbb7Ve#>*nGL~ zO;K|a`voR}w++*ygC(W3Uayp6jkwHk#)ys0V}r4Q!G$A5bNCt>CGYba8iic@pT5BH zk@6|VEn6fGGj7pH>0s>P;o*tcEVj1Rj?3+!h6L;41d*PmKn7-pV}HzMt^S{Sh=GBD N!PC{xWt~$(6967pU;h9A literal 0 HcmV?d00001 diff --git a/data/service-directory/images/cursor-03.png b/data/service-directory/images/cursor-03.png new file mode 100644 index 0000000000000000000000000000000000000000..f15de40e126332a6520288a33c483a4b5524eb9f GIT binary patch literal 474 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V4ULV z;usRq`gW?l_hAQ#WAi-}ra86q9XzO)-oRCw3(HrJ|W!&QKT+k+Y zbN1Ej*NihlPCeieZvLpZuZ)k8K{qaziK}}R&*UqQuExj+GA9WBO7@&5z5Kb$SGna! zv?fSjPSCx<$8y_o`E}R0yT)P;8|E%;$?k6xwASyipYKpy>Spxd?5nK{jGC^UoxJt_ zh9Fa=vsWe088AP;{ht5e%n%{lSs6>boaCLfI_JILb9D7ZMK_7wD-3olQlIy~jpq7x z{$9Y|3?_zoI;;;KDkiT?o5%X^_~G*xTBO%(4&&@TYNLMj_*3I|j2hRgUA{-!pAMHj z)_SSF>-xv@^UmyFaQSr_+XAhH1uOdV)-f=Y-(r}Pxa=HrR>OT>?e5|%hBYrbD*0DC gwQ`C6`u~e9NO8g4lVXl>3=9kmp00i_>zopr0C5`3WB>pF literal 0 HcmV?d00001 diff --git a/data/service-directory/images/cursor-04-cuttledreams.png b/data/service-directory/images/cursor-04-cuttledreams.png new file mode 100644 index 0000000000000000000000000000000000000000..f258d7ac4c0b84ec9944bfcbfa95f9ed1ac09e7e GIT binary patch literal 547 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V7%+; z;usRq`gYoW@52rfZS$`*O-bTjbZKF4$E`)4aZp^U8 zM>eo`ub}--c7^5QHrc)bbt~TUADS-Bw8ZF-*E5})pSYYDC1j-D&dxt}kJmS~I`LwS zWbCS$3V)Yc`_JKEDB+&-reopCiizCDEtY#1e3|}E!~M`cCzdtLKkv+2FCc3xYOORk zGVRUMo8QiL``oBI;NP)s^53R{IWO2<+&NM^=PI%X$K2(5*1uwJ$)Sskiu!YZh_1cb zS)`Iy>$7w{U*!tkM0a=*X1urmv;T^-8O68+=3(j_Ivow zKH8en@p?GR@V@{6 literal 0 HcmV?d00001 diff --git a/data/service-directory/images/cursor-05.png b/data/service-directory/images/cursor-05.png new file mode 100644 index 0000000000000000000000000000000000000000..fc13b37bfdb09832318322a51f295d921dac4240 GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V07?w zaSVxQeLHnyUbBHfTYb2PMt%e=L)>c=!G8d*jD;(-nehM0;kfE?{`@cCWJP?$-{_d^1%K z1s*(qygM-IO4x@D+gI{3?AZM8aJ~40o*&E9vsPEKRy-YZu+ednFM zY#o1_-tedAY>ZCa%f8D$>$AGh1G}rAxi-9Q_?XO+%m3oKpXALe{!jQ)91P&3FfcGMc)I$ztaD0e0s!Hmuo(aV literal 0 HcmV?d00001 diff --git a/data/service-directory/images/cursor-06.png b/data/service-directory/images/cursor-06.png new file mode 100644 index 0000000000000000000000000000000000000000..88f72a3abe26299a8d6675a8c7721721ad03e9f7 GIT binary patch literal 598 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U=r|j zaSVxQeLHQV_iG24}Ctj{E2xl7rab*r6fD|lFw03nVPFh z_nB{rHggq-v9em`Z7uTa0K4L$Xqj0)&ja3{xfyaaPUPbIDRj=29}ws zlV_+-R=F88J<{mplXI$*t*1wH&9iEmQr3{)aGpOwvuf4R8MP-DK3#da{gLvKk4vUk znm1G$EK*RpRWeD+|8%gR*r`ro*IaKghPv3lbM~!m{H?(&Cw3~MQtyzHq~-n80wtq^ zqKUhO&z8=a-s!43H*S7f*|l?VvMIB8LuD8kjws$J+rywJ@<92h=!8h4li5ZSKF40^ zGI#oQ(1$H!>i+3zVF{X6mKje(Tv)oxyrk*6w{ZBAPaGSN@wOH9%msuJ9R6Nr8?tbBy@|wd3T$g{pHe-&&&ZRF> za-?-CYNQ`^-8NmmyFjss;mgj8B^PdN7FM^}%E{buI;iAQh807@+JY0u>Ys;QxUu>2 zUg1j*q8|#(y4)&eZYJB4%RG%avHXzB+1*{sYhC}(+Qt4b{OzeJyJC157#J8lUHx3v IIVCg!0PKVD#~H zaSVxQP4+SI{&U_zZAN{To$}7A#D>T{Zm*%Hrrd{9s+y3!y#V(nHOv!uh%<`Ia ztVP~jQbb}}V3IjA2nZil<0)m|Ah3{)PpIyWOa!}z$)aPHOF1W`um_wDN^uC1stAxj zI^kfZd)ZFMjm#O09c2!O`e*ZS^`2fK#~N{&;fxVm#s*^tVTG-_$6qo?%=q|MAlXg% za6Ow&Cx5uCQ`TPx1Mvr+O^akd6=iEVJEz)emMykwnB%0TIcsj?-%qg`{UxU*B_t#w zp3R?i{=~ZU@A7+-6xH_KUi>KF$CDNYSA~l@ANODWD*T^UXx6{r-8Bj)1(~ycc60vz zZyjszxJ~)Qx$B*2o&V+ae9{vV5)vw|@9b`DY-~K3^i*!rX|74y$|(x+_QIOt6WBG1 z7?#LPXf%I*;v{Q|JL5Ww<*tRcTy6(7Bv?&Y8LW!RKGbHrwK6a;FnGH9xvXV089$ zaSVxQO-_(VIKYvtGE4QJ`jU!&D}VO1T$#WXkudFi^e^G{ho(mdOWx4G|JVNUZ^czs zO{{l?s+e~$8-1N;U|?|N@?FLc56(Q;^85aUdmX`v&Z)M{Tbt)MHa0eL9{aI!^_d5S z4-J^>KUuT=ds5EB!^2Z>>+zw)tlQk|8g^bL-hciVBw8^uGczCFH23~PvFJ5-oQ3Zj zE3`9MEm*pKB4gWnp|e8&=U)$M`JDN(dX7T#<#+$PIe-68FSsSBGe?8fVsXL&heeT( z{)-EL`(M7Ru1RlU!$j^|iys+?TwKMI;Go|nIpNd3@4}gFYmNLRb&A&;MO-+Prs1%X z_k6ad5y#Zs2UYKvzH8c?IaT_B;(@xKdd$t!l)9FFVd&v;*~XgCa4VOof(=z`)??>gTe~DWM4f!y~G4 literal 0 HcmV?d00001 diff --git a/data/service-directory/images/discord.png b/data/service-directory/images/discord.png new file mode 100644 index 0000000000000000000000000000000000000000..aa781929de59addbb775aea91e3a5c723f347601 GIT binary patch literal 638 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V6yOZ zaSVxQeH&(*E$t{!%f+;m@5KhkqmA7mg3r2E1V1)QP$}nAvG6Sj>Bye+X-9m*xrEbG zTbaYsR~LGjzI)`<8nl!{V?jc)b5y;F*Tgp!W%=J~Hu+_~2|xSx&ADpp&DPZil;y07 zo*lS#dh16W&fDs_y~g>I{@lOr z0nxP(fDok3)UTV8yoKa&6cX(UefZsI-h~z{{6aRnR^#?YS#Q_+%BJ0 zXvdkes3Gm8`OSU83r#f`6P~Q+c3ERk|6{7loNL++dzmU2&Cbo<-nd-z;MF@^H+TPL zpJwU0DLYzxVQ&iW2;jG!osrSp3N~B#k^P##z_Be=N;1}$jR6b=(-lyjl+oCPM8s50J zw6d@Ir*Gk-+Jm!aviLguUNTpE%IcZ_M7OiCcPb@GKB!+ab3u%(dglhaU^?dM z;usRqdUU#dhE$-;@%`aPo@i{DpeUK;>1Z%HNJhrn!JxU3=WgBx%PyB-4^ENp;F3vc znlA-(C*5MnYJa3~M6pRAhKo-r%}Bu{;Xs+jl7Mw$53P;SPtKWbB zx$nRKgK0-2HC5PLW`0|HK_jBeaq?lViv8PGo!oCVBY6L*%Mv>eH^s~3Jvh9a(b&PQ zX2XA+Tc_tp2R!IX`>lG};rZFSojwvgFCHFzC}!NS;gEl-Q?dj9cJ1_?t?p;H z=n7x4To6{U!&Qc@^tJPZ4STkw++1_8Vd}N>-@IqMoxVZf9P?tab_GQi&)|2r`x17F z&o~{he#d(Ax^vq;N65LE-e3LTq0aUXFSf+SKjfv>V#*h-_N79 zwtLEAz8}flxwujLYmRh)*6ZMDey3%V_IC12c#tOS-S{$i^`$e6rZy~`5(n?|EIzUA zbHn?zq}1Dbmu(MiYn&~Xon9(xb4^=WSotsij$;lB10T3Jw5>Y5`hjWd{_sUR{{MOY z)tf)0@(<^eCA*d$KDmMCYXF1BJdd_LU9W{6-eb;6xF*PV_2tV8>Bs)W{@k#O$!3!P`$%Q;JHoj0>hq>YnXhs33Gdw2i%^GK8}Zo3*=srEU~QoU#XCo~yW z`pmkS)pP1bYjdf(2=k&n@zF=qK1dj+$F5=w3UJl=aVApSa^*QeUX6mgch7H&&|NMi zz`SUWT(>`KSPENv9mkOdjm^7muRHVLg1-}M-nPE8OX8mE>^RuKG{5W(d))TKN0T17 zFf&Zhk@Mv_&mrh6$LnXh;0|xMx=@R#oOS%k^6N|E_xtj0d=SFief}OZ!z2c=?gQ?@ rXHp6#m@V@BpENP$tH-|3zs!>#WGFl<-`~%`z`)??>gTe~DWM4fJtJnM literal 0 HcmV?d00001 diff --git a/data/service-directory/images/downloads.png b/data/service-directory/images/downloads.png new file mode 100644 index 0000000000000000000000000000000000000000..d03bc09ba8de765f58bfc28f3def96311fffe67d GIT binary patch literal 579 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>VEpUp z;usRq`gXd#2UDQT@%?T;*bg31l~QtCaq{THTQN(f&5@GsQhsz~scu16v~-rS@{x51 zRXJFqS*CB3aVjtp*rS=%krTK)`^4^f;t zdT&asf0n(Ck>Te(+v2$^o<$bK2Fsk^`;?7AVeKIW-wA28XU*6)u1GDLl(>pf@Z_YN zCs~@WcKdAll)A$*Yer^6SXo>tcVhVKXC6D&X)c%=7t$R){SjN5s-Q)L?SgEsu*dFa zT-SV7dAK&?GdRWk$!9)Vb#Zdvc3IyO%z!raVx5Q7I4%fzqxzkrKy`b9?dvGONMnP2atWzrM3!^-CG#x&h>T+l` zhr@M|l%-1deoG%JxS*Br@72S`*{@{YD`<-reyi&Eb=JsSW{ZN7F!$ll*GyYE)qUNs zOu8y>Q?QD0cZ#RkwJot~GTTajU?79AN$H^IC nG3lxEdkSYg-M?)ALVx=y|4JW!Kd;Ncz`)??>gTe~DWM4f_p%1| literal 0 HcmV?d00001 diff --git a/data/service-directory/images/drive-01.png b/data/service-directory/images/drive-01.png new file mode 100644 index 0000000000000000000000000000000000000000..55192806b45bb7d0bb731041c4bc20cf52e16cac GIT binary patch literal 380 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U^Me| zaSVxQeLF?b|FDC|@&C#y-p)-kZiuYf^)2P>lOHS`hl*1>(m31v4Q`$ln3SsH*r2c@ za#O>axlU*FOSzL)R;@6*>v((mw!YspuY2G6^Y44rcZTMJ2|wO%S)xBlDbH&chxp3x z5nB7}?eksiUitA~a}WBtVgHf5dn;oOUpMaA6?~+R_k2<6T@}|o|LY#VO*wk|WS3{) z(qA7XHl^?M>6#%@Xy))v(xYtO>~b#Wd$#t8HH9;y_xt&OC@Sv0vGH>Lt=GJA-{!Bq z!w^&%Ib;8mrHrdim8yJ-XY>$^ue`qX2&d3bM~0vyZ@(@Rv}BklbJKFdiRKgQRj<9T zoG9~4flF!sxBdOH(l`CYPAW>exPDU|ito z;usRq`gWRO_8|v`*7>RmK?MaDR!%Oy))Oi7Rz9QsQEp(n!j3QEC7Len+nOT0+pRpz zuPeQsadl<$?j4=Y7O~Us2^ODx>XD>zW&0c%@qN>Ge?P~d{d_0xR@<;$4zucqDT@!IHKUe)Ngvwv?~YpB81vdI!H@3y@!xjOrDXue;k zV^Z(@^Lksk)Ku9P9#OcGuVBFZ=B)YRNmrh{y{-LjUB1)t_m3>q-s*j;nrc5eUdQl8 zZQ;5E2T{3HH4eE<1-(1^l5@^(H2WYX(0rloYKt{%fX|WXhor-VCznk>|6Iame}vlN zDiPNEuS4rZq@o!Z&fW53;d@mna7Vk2<=id5ns0B;hCJ-p)seF5O8bf{?SHn%YZYwZ ziC~>5)<%ADE$;nhPq{pRHXI}#c~4c7{s+Q&S@h&xe0CbHFl rr%%U8qnVp+!lS7&tadNYzhKupk;3hLcyU^4e~ zaSVxQeLKxC;5T|7A*8`(=jwj@KAUDm|#??b@qW%J0B~r=B!7$DTOCfs*SD& z?V3`eaj;v_xs69o=8|ggO9iILrUMficvYPjqzJrQ#P=@t{H2qdvR1}^5}W&O|K;lc zyZ`&KfB$hl;>4^2T9NxQ!-TSML?%V%yjgc;$Ew*3HT(B8o}PSR4}0ds_^ZA#$J1Ue z;y=)T{aj9HoF21nCN}7tNEe$RYUx?#DE7qXxAdy3)) zc)s1jIIWOR-_5OqCI}p!671j3$-ZXN)9q(;8GOzrOg&PXqt#rv`|{@nSN|9ntk?5D zYQb3K@Zr}I(YsoGwZ@Q_qz`(%3;OXk;vd$@?2>_;0Cn^8{ literal 0 HcmV?d00001 diff --git a/data/service-directory/images/flower.png b/data/service-directory/images/flower.png new file mode 100644 index 0000000000000000000000000000000000000000..c7fe40578a3a2d239cb28ac15bb58f0d3fb369d3 GIT binary patch literal 844 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U}p1l zaSVxQy*ka%Lpo66c>S~kl3aJYbU8$std=^rm2e;B2{ICSbwzv0l7bmZDMC+|c`tK* zso->RlH!X3zilNG9tr69T|0P?XHk*B!V5dZyrekx@I9M5y<+#>l{D}n`D5+qa)CPSIEu>1LF=%3)V5$DQ9{6C9sEVGt>0ZrHVOQUj_fvX)>R#E)J}_H@oavyL5EyxApRMOGWz=S4DR1a6E~MaEF|oQc zA}9Nb@bskS6Ti6%+&2YnUMa05pZ5M&p2?jXNgLO06wv&fqJ1>tT?W(&lc^odt6}{(4ey3EllF%6lTx66XYfYWPM9@ za|yGsjrk-ZID<9s3tPdHl zT=Uq@-J|}@w)v7dNA=xM^DFxb6;6uZmYQ!r&me5mu4jLZk{+0RQ7+xRf1W|c(d5R` z1_Q$h-p^bv>M(wI)%s`x%f#7P(+os6t#^uyNHIGR{_gf>_t=$eB|BrQUL{34Z#Vl@ zrL;j}WpLoCx%EF)?z8*dt8esMu=SDQF{^`BFV}9`{H^in=0XWZBj!tQnXdU=uDt!( zv}O9;sN#H%y8^CWewOdfE^3_EzpUlYo#fu9vCEaSbl%6!ejod|{ebodZ~5<6R|E$h z`})8%jwAKO)ugA3H4CeDuw3|hVu!!1o5zZI7hBfUzSZ}&rmi~5EE_63gxzHQuj@ds=8&b3Z5!Hw+<3=9mOu6{1- HoD!M<-K~wS literal 0 HcmV?d00001 diff --git a/data/service-directory/images/folder-01.png b/data/service-directory/images/folder-01.png new file mode 100644 index 0000000000000000000000000000000000000000..f2a9de3bb6574405ffe59ddea083ef604e604360 GIT binary patch literal 415 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V2t#1 zaSVxQO-_(tRhBgn3Yw5H?T7sIJAZ;dbG}k%iQtH|%U#c($9j(Ezh)_mu;OX|wbN29 zwnj~Be0(%YvX?VBYcc~^Y9mMqll+$He4^BHB65VX1~Vx=-%dyR!r|2elCAz zoMxH7FzZosW7{{kHlMxf5l=IOm<;CcyECiH_{GX+3@N7*Omub}-J33arT-B_%*BSY zLOIhC7bh-QxOd{hg`4I*RFgN)V}Gz|$^_LG9d#>~35=@Kgt9G}*O@66t@O~Hf2gUh zvW%0NnVI=;&--?Xk8KRhjXTtjE`RZ{kEg&)!`R}jM%L?x%m(-Sn*t3q7#Q|2-rW3N TbY=(x0|SGntDnm{r-UW|&N8D` literal 0 HcmV?d00001 diff --git a/data/service-directory/images/folder-02.png b/data/service-directory/images/folder-02.png new file mode 100644 index 0000000000000000000000000000000000000000..858f7fbcc02b0196c33e688b6e0b5e4e1e15cdb0 GIT binary patch literal 535 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V7%z* z;usRq`gYoWZ>B_vSy)RDTS+~oQ%c!L!#VNGituDlrg?k&fPsH_VDe=?N6moKpZ8$UQ-sR=D$|~!N zdN;bu|9(FI9NUv3=GH16@59yZ*W);|^DAt93y#+m{9N)+)K0wk*%610ky9>tiP}rE z8;hTOYTB|jx|(_OlfMs7bS%+L%3|Ik(fPVM+^r<(P{RwU3MCuEIF%=#q?+F9S!th6 zVpa-N7gR62F1lc*+m*EzH|m|5qympW37vD*)AQwfBXx#`?)UB|w=os$sMc3ceLvUj q2a9}rS!?~_%T9j#6AtcwAl`6>_fY-gvuz9v3=E#GelF{r5}E*YuVA$g6 z;usRqnw%iPsw`{pXtIxq_n&_6ynicyR(uuWj`$F1m%E-nZ|*ss|0^GIsMSm>-V<^9 zL*Y7suwAxVeEA%L+y+hzX&T47xAN$3UuM)%eg2r&;??S63)-c)+7mVebJ(2|OU^wgP z;usRqnw%iPsw`{pXtIxq_n&_6ynicyR(uuWj`$F1m%E-nZ|*ss|0^GIsMSm>-V<^9 zL*Y7suwAxVeEA%L+y+hzX&T47xAN$3UuM)%eg2r&;??S63)-c)+7mVebJ(2|O+cI#6Kd<&*N zb+Jw`VR3Ut5DoJb8#X&Kt=_+qS4!)(WLk|q%Xaa_ft}_ZD;Or|%Cjy`2w-4HR@9s( Ux+12Yfq{X+)78&qol`;+095j3O#lD@ literal 0 HcmV?d00001 diff --git a/data/service-directory/images/folder-05.png b/data/service-directory/images/folder-05.png new file mode 100644 index 0000000000000000000000000000000000000000..9dac478661f62011ae6fca3fb429b62807caebd5 GIT binary patch literal 342 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U=;9l zaSVxQO-_(tRhBh)G}*_*`%k}j-oKSUE4~VGM|_C1%U#c(H}@RR|CJ9p)M};`?}<45 zp>Ul**e+WwzI+ZrZUZNVG>zlkTY2=iFEi?>K7Y(>@oIIk1?^H??Fk!#Iqc4fCas9s z#&J|I;xfbW?yXx28JxA4e?Q%=krZ*6!S-N-HAA|Y3;PMq{>H{e$2-+#o}YFw1S&S< zS?rQftgLBxA)s(AaY+-SKeO{;#v^JPMPCGDnU+{IiELGIWi(`)EET1)oUul1f^cYx zs#A{G#AM5xd=A?u#GIDY(CzTpC=tHUb$SuQwFw8=Hnbh!?@VaxFK%7&jw6R*ap25@ uneK(w{PHtC{uKy~y1Y0+B!HKJ;b=}q?yUs{7Z?~A7(8A5T-G@yGywpj>3!D# literal 0 HcmV?d00001 diff --git a/data/service-directory/images/folder-06.png b/data/service-directory/images/folder-06.png new file mode 100644 index 0000000000000000000000000000000000000000..6e949f998e62447cf0745c7cde1806210424568b GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U^wjQ z;usRqnw%iPsw`{pXtIxq_n&_6ynicyR(uuWj`$F{Zl3|)@?%FT+WucDU=g-EU2a%l zBy*!eSo^Qd37LEjL2d&lhO`%YY<_Ipdc`H`eo7}Sy?9la`+_rXtFy)pO;&cZdnprQ z%7u;!MqECi$L2T7qM^63vGMPxSP{cDnGN$2t}rgh;1$CzONO1ij^*qJ zq>OGbT>I7_eYm`hSvo)HuHX#@x5Y-ym-`--$=Mk^{;jxb%QE+a8VjTt7~VR$-Zf@) SpUA+#z~JfX=d#Wzp$Pzpr(nVW literal 0 HcmV?d00001 diff --git a/data/service-directory/images/folder-07.png b/data/service-directory/images/folder-07.png new file mode 100644 index 0000000000000000000000000000000000000000..7b0eba0c0581fab290352d17ff1880d9bbe31167 GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>VEFCn z;usRqnw%ip9 zf6kS-^!DOMAKC;~GRQF*I9tZ8Nv+svI@R$`wON={tnEgI@D+we0>W=Zn)-`dCA6mN z9(u(w#pJ-pB;8z@0~1aisQalGW~sJjQ3(t4JBFSd5ATLK1&J>k*YP!|egWx_kWhHa z8N0aQ@zJOXr*_p-jQ-4v`6NmYtYCJNHF&`1u#&sZgXQq4%wJXs|5pC&d6QJW^4ht> zY|G*&9em5c#>Unrd7uB_Z0{4j!BNeO{>;qp820cARjGK*v7N)?XFW^J>xqf^CPoIg YOUYLZriPm_FfcH9y85}Sb4q9e0I;xsZU6uP literal 0 HcmV?d00001 diff --git a/data/service-directory/images/folder-08.png b/data/service-directory/images/folder-08.png new file mode 100644 index 0000000000000000000000000000000000000000..c3d66f130ea59a3e355256e271f5cdefc63402be GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>VC3+0 zaSVxQO-_(tRhBh)G}*_*`%k}j-oKSUE4~VGM|_C1%U#c(H}@RR|CJ9p)M};`?}<45 zp>Ul**e+WwzI+ZrZUZNVG>zlkTY2=iFEi?>K7Y(>@oIIk1?^H??Fk!#Iqc4fCas9s z#&J|I;xfbW?yXx28JxA4e?Q%=krZ*6!Scb=YavrsD2hEe!@4BGhg0D;{Xg1?aqlV+NHdKvBxcyZMp2xw>C8i m$G$sVD$EM zaSVxQO-_(VIMCs5bW!J{z245B%bz{I>aCM-F#YG2y>>fFt&IOHZ&RM}A@bbEB;CWu zcREG9{Iy*MfTWRgyb@L(`oV{&Iu&ZZvz`5Fn(+arh8a7K zi!)7W;X7BvAp3xeG2)yE?qhF za(aqHT;9=#3^SOrnx{txOG;_I-Z;y4$0Y{a$8tv*Kl`6ePZ8hkT_`Ote?WBW2Z0$M z{|f9`*>lHmq3MBWfs4vs1>fEpS-j1VQazz)w}64cY4;Qb)gO=EFfcGMc)I$ztaD0e F0s!W6q=^6k literal 0 HcmV?d00001 diff --git a/data/service-directory/images/games-01.png b/data/service-directory/images/games-01.png new file mode 100644 index 0000000000000000000000000000000000000000..0a7465a43e93a12ca1f6de1248fa499d999103fc GIT binary patch literal 696 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U@G!- zaSVxQeH(6=aoa(pR`1ZpWe#n-F7P!r8DACQm2_5kz^9e+;+f(V7U62omx~s8ehrzm z^onz?KxV;$TQ(UdE;J}syh-S>Rt@kt(0p5Qf~T+Hj^@%+FH0u*7kRaRYn=G5s zM)RY(Fj z*vT6i^4a9vnPlthB8`y8mxvEsx~+{un{Myk?mkQ=PTb)U?;?${RL*t<=gY{4K<=fbYHX z@{CT8*?!j_^X53unxeXVVz9}c-yaWU$G_E2Ec`ub?Ub4q$67i#rd;USV`lmKZ6Rw) zsIdKe+ry`KzfYgs^5EA+XPuhA&s-G+8kb%64HY>neDJee!};pK4=u(1PGK$*Er;GZ zZRgu~;3dDVoA2`3r!=MFUb`)MxF)M=Yh&)^zlj}dSmU<6I#%-kHG{yue>R8KWIg&F zIMcdrSwn+>c*)Ymy_;PEkFYp>Z?x~+ucvUWwxKmo_MEQ5#aO$SqH`L~tvvES>xJ-U z<*R!ix!ki3l3mah=6A6mPh?}v<~(->A-ATxf&V{B%g>d5zsO^CI0FL%gQu&X%Q~lo FCIFLoMDYLs literal 0 HcmV?d00001 diff --git a/data/service-directory/images/games-02.png b/data/service-directory/images/games-02.png new file mode 100644 index 0000000000000000000000000000000000000000..47e6bfb3c51e21d0846d9aeb2e5e26116a5140d8 GIT binary patch literal 507 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>VBG5I z;usRq`ZjER{vij6S{-kzH%CO)os{Y5^x~Pef5D=YD;e9)=&W26JT-+a&CF=h!-9x2 zPgJgodJAypIZjwL`)29&Z|m&W`Fe=W+q1jw{oUI8-}f=8%Sf6|?XUW3cDDN4%Ma_0 z1ael+`<%X1bn20dtaDDAbvU;8i!&%(So!QH$1E$8^ZegKKIw`$@HnZz&Rgive2&YO zf6I!F76v!F7i$igUf*KGyir_JODTxiX6Lh?GuG_BU?bmW>&2U-|7=E{RJ{^cN!J#R zSE}AyW&PQ73DdiEa*ParubEB#^ZBb-pRLz~=dA$^ z*-;#`syy_#-^~(Rm;Y|+$%)t6Y98L~u3U1LK_TPSj5WIp7Wna9)JbUl@waBCz=2Pa z-#I3#A5mP*`cUaT^BU!fBGLW_$sYukC44hny^y)<{_UeDSAXfa(drV)VZyWgT;aHj&(&|1%C}63(h*-c@caK^HZx-js{u8V7%$+ z;usRq`gZz8Z>B(*`$~iVV2m3kA_HKU6yYrX01xtS$U$c_HLC?7=(@z|Xa>+X3 zm{-h|m&wK6p4TDLZk8!<#IfbU)-Pv1->WQt@6-NEZ(sHE-?jGd_uhZc&ivfiSK(}Z9X3_; zR_1h{;@|9&=l3SO?e*BfHAC$phuX!C4^{UWL~R?BK4sK0)Tvg+IwU=Ley>-q?W(~4 zyK}PEN}1c+FiwzI$hf$Db$>C#furwC%lg=ZJG$m=Sd(dbXvO?x3r}%9Rb83QAf)`| z@4F|rEt+dKGB7L?o*~P8;PyAMSIaYf774QS$eFLxX4v-m;M2vKcJVq2^UwMoFMHPg zBx1XYTZXHDLIm&4S!cV``B#M{k^L88e?@`I|Xj z7khVVH@rE#_i}v8*@suyUF=N4ewBV%pZbD(+4Y~QRSYKz7#J8BJYD@<);T3K0RSoJ B_bdPa literal 0 HcmV?d00001 diff --git a/data/service-directory/images/illustrator.png b/data/service-directory/images/illustrator.png new file mode 100644 index 0000000000000000000000000000000000000000..e4f0a89f9bba604dfaef95305c6c80e5a0b079e0 GIT binary patch literal 685 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U`qFN zaSVxQeHvz)aoa)UUkuAOjgk`&%&shLY}lUiLEy!rqs|8Bp82*mF|#gp?h$WZenE4> z(HqW}f})xgqq>+{XI*d%*mJbGy~3+$K{NBJ?LuAB95Lee7vA5j68-W*{?6Us-~F)L z`~BUQhX1mhuNUnJR4bgY<@ei``TiRw$-jy&o^0ywz3uCFeer-cwo3Dtm0bdJ+T!J> z2ZUSSm>$pAkZZ>+-Y>_bU-#HOkAHeIb4sykg8#F5l@Cm=T>oU#{ht9vtzFjp@$u^&{|IT@_ZU#BQuc9WJc8rb% zQLi4JpM2>r=LB=t+cWmxW^Fj3L!{w?B9Frum=S zP*c?QcKV-igDnkt&t^@GJf8P#R;%so)ekR!)aCoCdx5X}-mFcX_|3aw+3buSZ6B6T3LjqZKdwxH<2^i1|L56>%=s+TdGH;*j%SX9F(1#euIDYth`@l rD>rg3e7T`(SGdNaFYixO{@{Mc{m0((y_Yxx0|SGntDnm{r-UW|tQV3PK9 zaSVxQeLCIVxkHL8r#um3STO7K zZ?o&q(i)$Z+oYV@@m^kO>P_ZTme;G7-LX2W;OKJZ{qOd9$+3)HMcM&u9UYZgo1a@= zn;{;=>{V^JVPWLe>Hi{h0w+FP&DNzYp3I!|ieYidrHpD#L5}Ne2PWm|Pkk~?`^OEf z3(wM&+Y2sBFkFoM%);=XJYV5*xWM*}w|BEJT={8Q#_-8t>D$xttcAB5_>|lm-itD( zn9JANdSvQLeRp9>xc2GX+^4^`ZA|IBYc@^i@8{pE?PUcSZ}84Z(n&hyFh${vWWnXv z2d|bZztK`ybd`Z&4Zrw>PJ7m-WTpkF3AH-}I9v1?lGqMRpE;jbLx90|?vKfjZ{Idw z5@^NA=qWqpv7|AB&89%>rz<~3T&uE4W>RqVG*ej~YV_(~-5l=uQVu_3qWM(TxEsvM zTE2%d;K!8-D^9q{n=(&QDl{xza9qhion2z{&dZ${NlOq?PtrJ zoxHH?f^YO(L58zN&(HSDsh|7su=|4dB&EVdRx?h-hh@yX{6GC!Jy+s&@z26n_uWdA S5oBOsVDNPHb6Mw<&;$ULISB>; literal 0 HcmV?d00001 diff --git a/data/service-directory/images/internet.png b/data/service-directory/images/internet.png new file mode 100644 index 0000000000000000000000000000000000000000..7a0bafd195449a8151388f56ad582620d0f03243 GIT binary patch literal 855 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U>5Xr zaSVxQeH&(&aoa(pR;ww(d)HD{ZY_fyDH}B9wp>lt*b%)=OzMhIlE0d_!{n)+6I4@H z=5h&gs?2tG<}4{R=U=$PIYZ$=6O(6~!{!rA%~lcRmUBz`=9GBfFWIO6a_|5DyWca* zSuZi+m)s@Tk>q#Z^DD356O$wQ-|af)M>>8GP;_E!%VW9R(Z3*pQ?Bm)+J(k;2j|p@ zZP|10jFM3N3^%`y*RM?PO7rG3Ff4nQ5GLqFlzx>GHP=>o&dHb%8Rv6Y zyqQI1GKxXK#GI=91g0 z_ecF0xy`&k&7QK~*iLW~^Mc>ym5v$>?~B82mmlx#xBXi(cL!U;GY8jDO?D;4Ev%l$ zk^&1iZ&5l@@Y7)0&KD2(!;-TZR*1%$u)liZzENiOv=E2rYYYt8j}>{-wp5llR?QQ& z`nzd&m%07E$FEmk-|=RhTaxa2^@SEE_gMxcD<$bFIQ>{9@Ok6w%a3&<(v$;5cHjS0 z6?FQw=hj8tZ&z0x5f9LWIJ9leLf!0=OS-4KJD=1kvhSb3%y8qq8t0Ez8J%k5t0qgB=Im4c8+EgvrGLQ! z-E6@}>#F1|n_5gbl>`?*KV2d#>Ed^P;;N;a54@934C($WA96=WA^jyMLvT?L>*<^T z{tdY+w4NsXUe))tRd&~W3$@i=mK%Pvy{$ib*3HMm&E#c$@q%M_@@MjTIjuS{`M8$D zg-=yNB^SI(3Ysr|xHf^MPO<$i^ZZHCY0Pzs?zayKrR!O(D135=Yr|BBii-*gbrl;g z9edZv-%`xLFfVl9gU7!uf9Z5y?|PS;Boh=nze0K9naHBg1@qqtPF}13hNClG=)j>1 zy$u443nVvJUpA_nz;JP|BIll)|7J3@9Pi_i|HiRt$9d7e_Hyd~m~xbQn6>B4ILyGn Oz~JfX=d#Wzp$P!P0e2Gs literal 0 HcmV?d00001 diff --git a/data/service-directory/images/juice.png b/data/service-directory/images/juice.png new file mode 100644 index 0000000000000000000000000000000000000000..95b88427b744b1e96dde2e0a90d47cf7cf611180 GIT binary patch literal 809 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V0!H7 z;usRq`gXd#hjgIK@%_^ts0J@MeD$EBLPz()Qjg6~rir=eh|F4O;$3W!aZ8bFX~AVx z=aWiO?5l%9WO`CgD2U`7(0d+a74cFxl8LKP&YZ>SXvt2#lhyZP-`$lzd#!HzlfR$t z)$V)$z3%&C)*shRg-RM{2=G?-1kZlq=id-Ko1x)t-=p6<7v4T_y^QruOVWvJjc0OL zrdGAriK$qgP;O3j@aZ^qYaN5;#`AN8Q@(S|Vr00%c{GnT>1Esn)|zc<`ma(2=+AUSkl>b+TJz&{mZ%byAlG9Rtx!)ey9dKc`xB6Q3n~&4wQF_6b zZ?d~C3*WGQ6O_C$iM2IIkk#{>$%7e;K_xH5=T+`GlpkPm@m`|%_2f(j>1oeJyj&e7 zv3Fg$e1L2JMSsf!D|Jr?&Uje)lzWnc{Jm=9y7%|ky<8a_N*4C6{aL7>XW(m5cBs_W zKk*2Mrq!ZJb?cHYgBL;@)MQl4OTKoPUc)Lr^TY1gZs@VxC zjhPQr)+X>tTK$_C_Tj~05n1m)JO`NFuU>APJ4spj<7_)4jq7eDlfq;kKV#bB+{tl+ z_g$ugW%RQ9ts#=h!8XNujK5fa8!0R~HErXy3xdgKOb@@!JbyI$Ox=Sj`G9lNbR!ic z6GRvOeDn8!pb2x@)Gx&uyt1C&tGAuvewTS5j#($Se2UU@G)< zaSVxQeH(6@aoa)UUr5i!Wlq!iOt%PRET5s$eDab2$Bs6UP1PRSU7dSVd`?cOFnW89 zZ);bkYa5GE#f5|nUna+UHY^Vv6k~5SFue*XU6=Fh?&X;9(atzS(KzGbyDVXe>X?RZrkGXtzt5fY zMTg_EK~L7XnRm>8`Reqay7HYbWQniz{_D>gZZ%Hv&EmYY>}*bdaDL!f%L}pIoa?gA z9Xvh7UReE^rK?!qa( z4j11oD%$qsOjffI^h$stYM4iKfTuR`~1CR3u|LVF-0Th zeaA~e$`?GUtky~55!}gB=+bb}ScLb3!;>O*t*bxXclX@ZulvQ%w%TVI`BgB)Ztd$br%;foJ{)ofg|O>Q7#6C zyIVB`b>3GBbWRsLAau~#y4rK%<~^cwmnmo+-Ic95wN*D?{6OB`W2OQeS7W_7C!buh zs6c;4#g@H~rSGvdn4htWiu>%b>8JkvN!J@A6lGdYPIh=@Qy{BxD>f}mD0}u_YOuMTUn>&F+qL7ju|@-*0FVdQ&MBb@ E0RPoDi~s-t literal 0 HcmV?d00001 diff --git a/data/service-directory/images/music-02.png b/data/service-directory/images/music-02.png new file mode 100644 index 0000000000000000000000000000000000000000..594a9662307c7bbd41e26b6594b469fee8717fe7 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V2bl} zaSVxQeHw0!Pwxf6+x$Kz)RatIte7h(;=fg0S8ZXl zvcB6fXCKa+R@b_BYdSm5v&ncJuxTpa%H^*o%+ZiA@#c!?}W1vch-;0|+ z7~U{7-0zQLWbj+xUszQ;=cO%!&6K?zkHc6Nyi9z;sQmxt{jN8ByJdffci*3wn*1+E z{Fcd-b!$}`Iv*5n`EOb5xA*qJ1<%uNEnzux+}go1*FrnrE&17Ao_|M^dvvTPM`$^; zL{;Bu> z!q3_(^mJzOHa$ikmeaMTGsWk{doaAtD1P_zzJR#UfsVy`9kE>zKR>RR-TPZuVRd|4 zzW;occkwm97WvH6R_LFT`1hGqARXnfLm}jM`ACi0D)I5(n zS1QeH%hKNsE8g-|>2299926&F9G|vS@%@68v-ZU(?_(EX)DPO?mdEvo{nR3+8#4_K znFR@k-edmQxyW8_kAwLN275h5hRN&mm%P@CP3yVAtHo(_abnKW)ZA%2Ri9rQ6|P+J jHcoV9&aQgCdWNK#N|)r0%K9-dFfe$!`njxgN@xNAaV3P23 zaSVxQy&AsX`>=z^Kdsh)7BMSME?Jp5GBH-WO18|7Zuio-bZKew$t8XZ^%gmYE=iEt z)DbN!vg-%?4v{HbOT|hGIYK6Aag=7n?b$N@^-cM({V(6`E&pEo{hewh<1(K4J`g%f9#pQ@6P{;jB&gITK|~et*cDa zTGc+$s9@&@n^Q#zGmcN#@c&BfvSRLgTNyg5W>oR|#2&a1e!wY&`+dK#n8VfwXBEEv zU$6b5?)gvosh!*rRkhMLgnMESl$)#Am97?X(@3>sa@IV(ar1+(B2J86Tl;d>*gW7d z^XdP{P$9NZD%84K-_oSldF7WmE-w4lzIT|cP@dZG_W#X8i>;H*AM{oh$Juzl`opMmyaOVC?a9 zaSVxQO-_(twP?8fRro)z(5!!x538{nEaFy~rTQ;DAtAwH{n8T&6>sgBSLS>>T^@L5 z_Q$^hU9ysM%KlG0I^%-w{Ow=V5ARuOFDW4*A@S?kt%+yyGV)V?tXzHOz<~n?E?l^G zV#2}9@A5bQ2tU-*NYdbIXp|Q^n6lZERcD7vpZ_(r?!UtQsc)vgH;P!`DtJv`f!KE;a_L#$WAWdPH z#3p6t<@=6JSRb>kqfvJKSCtk9#p8m^3XxMzXeb;Lin-{-rJ%(!LDy+}k4U%TQ|2r? zMJtwqNS7=Qhf_VBEwT`@1|3X zISn@iocS4dxieZVsOAuO%MjJV;OY8t0}o@9t6`AgzJjA}ltUsxqFA3VJl z(#7MF&%UVHXRrDXS%(u0NesWA?*6ck(JCV&-z8H$=}XT9Yu+miEmdxd85mB8T=RTA Tjb#-B0|SGntDnm{r-UW|AZWTx literal 0 HcmV?d00001 diff --git a/data/service-directory/images/notepad-02.png b/data/service-directory/images/notepad-02.png new file mode 100644 index 0000000000000000000000000000000000000000..2f01104189c1d4190ed393905698f5fb36d786a8 GIT binary patch literal 529 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U_9;V z;usRq`ZnCqgDFtrUzfuy7RQVYicw2AN+wQ|iOQK;kjdfNbl~AMu}lxe159FlWc4{qnb@pN5UwE4ZK-}kP(X5+ahWNP55Qw$B8lWv%u z?}$7hy_%t+XU5ToNjFSHgPFPNrj_lq)D~M~WfQlixNzo022;l66V`=xDH=Kt3TBoXFhnn{8~d;L)htZ8-@nQi_GPd?zTKt>k+GZ)zf=N;~aA|=Zr#En>zL> z%EAT-cbHWQ%Qx{Cs2tqNp3t#ZhH<*ZWX8?1>*wwi>(f2>!s+GZPA!S=;VA$B literal 0 HcmV?d00001 diff --git a/data/service-directory/images/onedrive.png b/data/service-directory/images/onedrive.png new file mode 100644 index 0000000000000000000000000000000000000000..3dcb8e7d1b669057c389585f06b0852d16165b1d GIT binary patch literal 677 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V2by2 zaSVxQeH(6{Asi_4FQ~~>#L8j`AD=FJ*c9!fidPOQY}pa=BI0Dg9!C$|Ag-emG*60@ zXs*4$=CsgaNr}iDuiYsdCwIASa5{Lnr{%K>&0doaE4>vy^<>w28KkX=r-=clfj3J@&RlAbXH3zWp@FrF^2ryAJ5me$mXtmCe#nI3!3FW^j(s10cd`l?wmU!RY2^uAeD!_W zF=<)lM+QZa9Gw>r-e3$4nk&Gt!r=UrN=@-(sU-Wp&Cv|TqR!z?hqm*tFZle9yRd$f zMf=QVWz}`fbDoPE9NBx}Rk?A=&&TU>H?pkD?d0CKcGl_gTx|n~FouJg7H`s2^z8z7 zeEK#yY{E8nBschq#6X`^}0&3(iEO?-cDUpp=>yJK7H!^_2gbqcup zzAxD`r)vgC>iV`1AHT6MBs_b-k+3bL@Ue(Y{*NzzoK8H{wy2+fr_w=0Q8n+vLL
0SHVCon8suFxdUz`(%Z>FVdQ&MBb@0JIZ0)&Kwi literal 0 HcmV?d00001 diff --git a/data/service-directory/images/photo-software.png b/data/service-directory/images/photo-software.png new file mode 100644 index 0000000000000000000000000000000000000000..267a5b843d9d5c7c64bcf3b41b86b619a442eff3 GIT binary patch literal 652 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U~=mczxH8SFZ$Eltq~GIFBkOi>n)6ICzrd((@_lZ2}xl%dh)1Dz)%D zOWmmJG}+OJ!z!)tO@Ku+1X780@SUz9==Pj$FTnuaP-&gLJ=00Fud{~yj zz;pSN?<#W-6|iq)$UDwxaEEd0pKPA;13zyvI$P_%4!b%xRkr50?R?V%clGU^7#X>~ zZxc^)*{XGG>8E$w11v92@IG6^?egCi(%?eLD-ms; zw>Av3uWmEBe$-8);oXd*6FGbW`IrNaITXBHylPGcLxBABlt}elfq%a$>KEqKpZ`{W zebv5gzjhos<|=+Vd0+H~6qzGT7bLGAS7kWGd7FJ>;l;0CZ|g?LY?t9Vx?>{4ku!VL z!WK1N_CGhhifv>3>ZH`P1xg?KqWj9;EM+)kvtz!WedkokhhKJo{$$V5u=m??jpEDc zhZg+2aPG9Ro$-9f7}trxA1|CM-np4oL2;e4H=|1cXR%1;kNu2)DnBqi%M6{7A9j16 zU09lmu-}Xl^Cd>YX4RJW?EZE=~OYrb>VrX+f(V2bl} zaSVxQeHv!yAss03FGxknslDlvfcJWig(58`&Yt4pcY`?m4)Ly?$zwG|k8!zjY>Up( zgGuTaA1a6_G2RW*@H?i+n_}2_fKyQA+|gN2t!DiH_)hQry}3IVJMUNh{_p#zeeeJN z|Nrkh^M7llKMLQ~(%T$2)$fxRJnQ@6Nqqet>Df8UzaKIB7n!Sk|JAJO?aP&2eQxkd zdmn#O9bL=MaN`ocZnEI5{^gC^_a`nfDUniD31W2!j{X1nMCr8Vo;mCj%cWFbMzyoQ zNhztaSNPQ@y=YvZ0U-_!F(S+s{3r)wIg~)`h6pfeNS$& z{OH^qp7XMO-62`a4d0gQ#?)-FY@T{oI=q*N8oITLI6 zC@^X2BDo$0!8cDhPBWLR%GjzI<6JyHt$arBJ%-4yJa5D_TxH{b$^;G_Y_Ib+o=?HujoY7oo2C=CGWu3Y;(j@nPr=>K zZoV>_w{MPUmxML@oekyHQl8VZckFu+{bqmM-ULg*RqPyl)Ys|%@|d1|NX;}v@Z{F> kX%dysypPx`i$BzN3jU+4G&!$ literal 0 HcmV?d00001 diff --git a/data/service-directory/images/reference-software.png b/data/service-directory/images/reference-software.png new file mode 100644 index 0000000000000000000000000000000000000000..8cbed6bfa1ce2419ffa0a41f5bb7ecc37e9712c6 GIT binary patch literal 798 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V7lSy z;usRq`ZUbYLpo66AJ4(n!3PyZv?5Lfcy%68^<~fZY;$5=7{tQwGnvP2VMm@{necQE z0U_ffA&v(RI%X(#M6PpoS{AVIt+^1iWfJRC;3X=Xdw^?w)>Q;Zk{-^7s3{ z-}}G!|L^?=K9yV*8MIP>}Y@VYI}PBuA;h+D?2~@Gc>C|)n~WI z=G^9|AJ@%cKJa+D@4Cu$EG?7S7#?ggxFPB8$H?IIQ?B^z+m!C<>b?h7ZDmTZ`}FMA z26wxZyHoT!`dWIbqdyR`qjkjMiChXnG@MD4dK~v85cp z{|;N-5_aS{{^^CPx>&7bf|i%%zFo$iXSb_5%=!Ov&W3sOJR7!ZC~`KGz2%rT$!J@d zD8mL@#VwO`dOEV+{S|oTb}q4+yXS@dn&53MDi3n1#TXp!$o%=$QR3+0v`g(^lhB9k z(4##5+s{R3yZP|qy@HuTY3-O{H7D|a*wenzt|HY{qKH!b4)@QIGC5oZ0L2UR`R$R zrX}}Rw(1}2)ZX?xEDN4GTrD!4$r4eqccyV~Z&5_z8&(g#DNV^Cd;vleK3U~&$bGBj z;bFPQ<1FK>d8ezbBj(O)3{u;ia@j7gmt%5+@Vol|j2X6$R!T{lJCl_vpKh4;ML4X$ zbHW6cCEQ9aCsy8@a3Em9oh$~KSt7PfN250Se=uD)dt$@<_S?OQlMbwimZ=kssysXG z?Xzopr04Wu0{{R30 literal 0 HcmV?d00001 diff --git a/data/service-directory/images/roesbudtrelbg.gif b/data/service-directory/images/roesbudtrelbg.gif new file mode 100644 index 0000000000000000000000000000000000000000..73c03442023848265790a922983d00f216f18bfa GIT binary patch literal 1187 zcmZ?wbhEHbOkqf2*v!BXv~+3l-o4dZ_x|mz{I_Jvzl$gT9o_Zs{;mHn9{6htJj4m>alzYJTXIH&vSt&HCAyCVV}qKsxeKpSzi{f&TH^cTH-_ z8=JhHTdTF3ExHrQRoiB&FY#QwU`5NC{&jPfuHU%9 z$JfAS`?j^qcCOqseRjOP*Wvu5sosTQ`4MNLB2S-iEzHbKyq2=K>gKZB#mjr|U8;TD zeYc?Q#mh$)^|RgHJ&^kteZY_H$B*{5B+E6aB9VOMrEgF3I2vPU%ORxr*C$es<2?9+P>E1i@rSC>V3(t z`mn&W!#e~R8j^4Ea8^eeE<2FHE+Q0L!QimD@ZzMntH0LVnaRl`8f2Qab(Znwxb<`Y z-by^H)>a_N#Np7l+S2#co_)6+{GAW87c+B+6_|V8FD)&XQG1fl(jb~@d+T=eYD4YQ z>y)DA?AZBI@9ccTwUcfds~i{AN86sJE_iJq{yr+M1kirJmnsqJ^$Zg)I?WSP7|@SgdjK)1UU)~_NM z%3p01ep0KzaB|*+nNPwcCw?&GY@K|r(rAIRjnI?F1tPwkO>OH6Jr|_xli*167Je3{ zHgn^|CET-Q)@3f7$*X7jsPI_B3&nJ8zC}ts4R2O1>Z!Tb!MmX0QO1iXySnL*9jxCa zE~)l#;(EH+cUpMn)WCm>pDdjcX{k2vPhwO|I&X7@clZ>bMHox6Bqi1e`sZQkXQQ@ZRIl{}u3(W$yJ)O(+vPRxp5)myL439c}h zmC*dIGCxf@XV+S>^}S_tSC-3Y+%0b3^X2s>@AmKas<@-)zWekg;`8~BDzD17bV%~r qJUp80rFkjYZrz;6J@)(wPp_P}{`zHZ*1M2riTUeRu?jLUSOWmce_53P literal 0 HcmV?d00001 diff --git a/data/service-directory/images/speaker.png b/data/service-directory/images/speaker.png new file mode 100644 index 0000000000000000000000000000000000000000..80537f5cb6d07d721d40431299a64e8ff53bf1ba GIT binary patch literal 640 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V6yUb zaSVxQeLHPqc5tA`v3fznxAqFUqB<;H-b<{G_%IsIH4-V|ShAp(&sWpJL(oWdCKD^S z-?fFjx+aRwTz8FAy{tt712j8y#iZuknHA1e_~EYmz1r{hO!RM_*}ms=<(|*A->skD ztxjn9FWZ=?>g9e(Hgr!(gi#TXj)Oq{+o(U8=O^|~$xwTI?l*gUy_74Dih`_X`L;4$ z2L7K%_TFZQId{J3`%(9`9nyytrYoLc%zImJ^z5UmgWCIhwdOkyy!kL=c?fYuOtNxvDO8BNtEYjkVBF&A z;usRq`Zi2A=a7R$t&VS3w2`5jfQqn&pI?&N%)`AbOv2uVDOr;isEG?Svs`RAp1X;y z)4`y1M#P~>Y>lkPU0yED-Y;jn<6Msa*XNI`*MIMOFZ-c?e_zXg$FHk)^-jJpXNJ9n zsr}FA5A4i}yk9${|IE#|eWqlx>VxiI(S9cDA1_qomc392U$EC=a-PY0o}Z;<0czQD zoMu4|%6q$fV)oauGT7X;TC&nfo-O-PI!bQ6B=GAu`!3`58wuRYHOe(}*1U^PxNC9bc`m~P z=4XlJ@@%PMI~J%#uexxY&2^KV7T>w1Gh0}jO?R69vs_RkFfqbxhv_b4{L-S_}+( z)WcL0ey;U!dDDLBUez3f8%^ma)^mU8T2SysW`ZE&(cj*j`xsRPHbP0l+XkK)~C{^ literal 0 HcmV?d00001 diff --git a/data/service-directory/images/torrent.png b/data/service-directory/images/torrent.png new file mode 100644 index 0000000000000000000000000000000000000000..d446cd702aeffd3340ff53749e40e45f8ab2bffe GIT binary patch literal 805 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V7l+= z;usRqx;ET4LpV{QZe5F-W5J1A4bBRMo*I0C(-l}&FLk=`D9Ewcs$%&CM->5?uE_y& zm}Xf_Il?oMN0!B!<%|&f!G&#ilDH&WL|h%;Oo`E)=Uf#3{`v2ne{8(p{oeijRpkB_#{TPynVlNrNfyNKgGOhnP_*@<#M>guM}Z}TAm00WX*p@)pK@l z*zd2wz|d!WnxR3Ir{UPkJ+odYcgch>1U_*qewJj@^zNpy$0L5l?@X&2M0r-st}Ikg zc8Ym2^^WR;40RKu%I1BMoXbwwrm?Q+h~ZpzV&|m=syA7lWQV>|j0$6JShMKXvGe-> zi|5*&(|P>*mxkX5ot~?AMe6FLS(gU2KV*K+7V%NzZ=;pJ^428%nhwQlj6zd#Z|^$I zdNWacssqo>#OZ&UqnhP}l`QgEc!iGDU3@I~kb5qtr{5{Ju)vjJ3nuFC%NPC}zpCCP z^TMPPr`H@j$n;k1f=h*}y4V6o&SgE#e{)^*pR{D&&`J_2IHbjv+DI4yiu2SANSw*weq0rIi~Q2$c$xziK_ND z?x(#=fBsFfn)&rwt+GP_!nN;h7f!$DpmHciJT^a1;8PW|+?s2bkMC`&mtuVIh0UgD z`PYhR!dwYo*_0yI9^Whzd_ZL{BX79T#>F;6TAW1IV;*qdcu!L{C>{0?(xRB88^DKjuI OFnGH9xvXVEp9i z;usRq`gFQ}{vij6WApV?Sexg>%I0knYJSSib8+p;o6o{FhXjVmo;-7C(}Xk*yMt;G zLBXA_z7rI_aT>Iyc&caYUR-|tTZHuyIp^y7in{Oj_Lhe~*zYa$cERc@kA0`RQ$N{o z)ja&ax>L%&>h6-9%~6Zjm28Y$Th6NG6gc5d+mgbhBNwg(E0l-bsN%|5-M>g-CT~e7 z|K=Xg%Ri=1$^BZaxMS+BRqclhXWyQfJ}XR)B~-9|PU<}KM>-rqDi=6U&xy%c_VDqe zT<@8)+WJ?YbvI;4-|)TeZif2IDJhII<37%r-PV7tyG@MY=j-ElX8BDjI>TjHP&!FZ z!ChZ}+K%ni<>WBZb>L&Yfv z*n2VJGG|V@L$20T#v_6qqUS$eR0^2-?OWsRbJ;-?`y3>bWPL(dUU>;yxUo#=a=Iz_ zK=$+*(}3_<)yMOuE@HT|Q~T~*JBA}Bf5eouOJ@p7uBN`u6bP0l+XkKZc6#{ literal 0 HcmV?d00001 diff --git a/data/service-directory/images/trash bin.png b/data/service-directory/images/trash bin.png new file mode 100644 index 0000000000000000000000000000000000000000..a8437c48122f1bfe3f2b5df01e4ec29f01dd92ba GIT binary patch literal 487 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U|i_w z;usRq`Zmlq|B!(|?aB#3)Bd$?+E{vK#!~J53sp~DTBkF0c}wS7Wv0;3D?C5>LrzVa zIJJ|pbK(AmR)tV6b`I5J&-+(|wm;ML)cdx#JbnIohh{e3f7UveIp;kV-E%f>P2c;; zxoJ-}r+V4=RWmfy>^+$Joa<*5^8r?dH<$PhG#zs3xTbLaV^`rV>j|M7y{$LoU!SVZ z(4uoeXrasl%eaq!UQJqJ^rB-&z{KgA=Bn%s1tv$FZ`#hMBd{Qj0Nmf_p;a<&K|`L{DJ)*ZSikl?6zi~kVMhl{tn zMdwB7J49wNRmW<4Kak%na^U)($7k8^U9^*SznRS~kh@RlWR7-8QLR0zchUwGwayh; z0dhxwJD(7p7H1)~YMHj9-oeZ#%bzH6FPS*YX$IrXht96Dn-=_9J5x4O)Ij}~`x}=a zbsNjn%R&NYm9rnDPnFAmG+~yrsoFy!m(M4HOa+4lL&8n0I$otDZaS+I>8)1(Cxk8J rJL60LxRx_BJvO}jyW!yc2i)h6UcA2XMV=i40|SGntDnm{r-UW|N2AoK literal 0 HcmV?d00001 diff --git a/data/service-directory/images/vpn-software.png b/data/service-directory/images/vpn-software.png new file mode 100644 index 0000000000000000000000000000000000000000..b847e2c0700fbea9d529be43b0309111e5b8347c GIT binary patch literal 726 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>V4C3R z;usRq`Zm-yTiQ{emaFaaR=r6QAr>4m91*SDs#i@7Gbd^3@o>$EQTXwNT_)t^I;%CO zLQ^;Dl(PF+%RK=T|xJSnO{Stt_#Z!A-v*KCbN|x02J@YaVrO`U&P| z79F;lAUgFC!_-F%>)s#jGT-$xWG-jzqn!7;4N@`po1@nznuIs>HZ_PjUH`tWPS|4V zBZl5Qx%BFer!7heUzm1W-9KAcW6r9{d0VHQQdECrabdCmgUsbg-**-k&e-g|O+h)Y zr|{CzLXO2dnM!v5XIlC6@YHkr6?}`GRQLV=rL^jUNRIDnr@~TxhB?a$%>_z$7i#_Z zTgdf&Ui}3YvBz7M7O#1n?89f@er(E|mVgS`%R=kkyUtNqA$j-3v%<>yz`RB43m3fd z^l>`AR51&kaRdw~-wwUZ~Zbol<^W^g5B#X}K>o3on!)3Zz_Oj5cs{s}}|C@vzo*SaN zCcW&W*z#!Y8FS-#ORcAVe*HALW>yUcLq+XR=F7W}EAno2DP8Nr{>aS!ZWQOowCCX; zH;1t?_`H{Ej#jTezQtvKaQa*hTemG2f8N?Rr`Sh(lV#$u?BrwFo3sD=*?w6!XZ>6E zXG(l4ETW=1CVVaJk)Qd#U+&1o2Q#KA=(T%Du3G-S{MDL?rvjfZyJyRN*7LXF{LRVp zldmSnPH~y{riSzEWM7&2IbUQtTpFxr^7);(*=P|JmGILu;q-)ear>>UN@J3D_Qfvq l^Eh$q;=1he?%AF8GdK_Siry)j&%nUI;OXk;vd$@?2>`~PN38$= literal 0 HcmV?d00001 diff --git a/data/service-directory/images/whatsapp.png b/data/service-directory/images/whatsapp.png new file mode 100644 index 0000000000000000000000000000000000000000..19464ab66ba85558935cc6a3eebe252593a35c75 GIT binary patch literal 637 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U^4e~ zaSVxQeH&(&aoa(pR_{>WH6Arq-dlS*CoR0Yr^1xw)y4-Cnl!&9*;JZHO;*)tmNB@Y z@gPT2;?hwCjhmAkS@PdKY4UbvU!S?)0pCSV&+qS5R)4x;_u|il*POvETDy^8T6~kFM!1f5xqOvovq7_lAi~w_bI1Z`HcK zVUCvPnFH5!mbdwBY`;AJ?FY6)P2z`gm_G5p=l!bOaD}SpSGq)WBwlQIjg=aUUQOvRPd)|SzRYjJyW(_Yf*6^yfEn+s| zO9Z=0r!so-C^*RVyNI3P*RL?zeekH*Z`%X21=S3dF2x>iI_|pqQ1_-k!Iz!YC$jbx zx#jgFSuErDVg2}eobN1km4p)WQ=(srmaTvE?~RvM(`ttgM`v+<`4pv=w0O4y?>YJW xBHvogJ(srYDQGk~y$YP;#$xnupV2{i`HpWdH}RhrXJBAp@O1TaS?83{1OV_;C5!+7 literal 0 HcmV?d00001 diff --git a/data/service-directory/index.html b/data/service-directory/index.html new file mode 100644 index 0000000..69c9824 --- /dev/null +++ b/data/service-directory/index.html @@ -0,0 +1,48 @@ + + + + + Service Directory + + + + +
+

service directory

+
+
+ +
+ + diff --git a/data/service-directory/style.css b/data/service-directory/style.css new file mode 100644 index 0000000..7caae9f --- /dev/null +++ b/data/service-directory/style.css @@ -0,0 +1,60 @@ +body { + background: url("images/roesbudtrelbg.gif") repeat; +} + +header { + display: flex; + justify-content: center; + align-items: center; + margin: 0 auto 0 auto; +} + +header h1::before { + content: url("images/angel01.gif"); + display: inline-block; + vertical-align: middle; + margin-right: .05em; +} + +header h1::after { + content: url("images/angel02.gif"); + display: inline-block; + vertical-align: middle; + margin-left: .05em; +} + +service { + display: flex; + flex-direction: column; + align-items: center; + align-content: center; + margin: 1em; + & a { + display: contents; + } + & img { + width: 64px; + height: 64px; + image-rendering: pixelated; + transform-origin: top left; + } +} + +#services { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; + align-items: center; +} + +article { + background-color: white; + border: 1px dashed #fed1c9; + max-width: 30rem; +} +main { + display: flex; + flex-direction: column; + align-items: center; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..1a2da29 --- /dev/null +++ b/flake.lock @@ -0,0 +1,251 @@ +{ + "nodes": { + "advisory-db": { + "flake": false, + "locked": { + "lastModified": 1766324728, + "narHash": "sha256-9C+WyE5U3y5w4WQXxmb0ylRyMMsPyzxielWXSHrcDpE=", + "owner": "rustsec", + "repo": "advisory-db", + "rev": "c88b88c62bda077be8aa621d4e89d8701e39cb5d", + "type": "github" + }, + "original": { + "owner": "rustsec", + "repo": "advisory-db", + "type": "github" + } + }, + "continuwuity": { + "inputs": { + "advisory-db": "advisory-db", + "crane": "crane", + "fenix": "fenix", + "flake-compat": "flake-compat", + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs", + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1771194746, + "narHash": "sha256-U/BvGW5p405bbsxd8IdMHbSUNVXsLpgPy0ieQwEh3mE=", + "ref": "refs/heads/main", + "rev": "4e1dac32a5c0bf71021027bee35eca53892b069f", + "revCount": 6085, + "type": "git", + "url": "https://forgejo.ellis.link/continuwuation/continuwuity" + }, + "original": { + "type": "git", + "url": "https://forgejo.ellis.link/continuwuation/continuwuity" + } + }, + "crane": { + "locked": { + "lastModified": 1766194365, + "narHash": "sha256-4AFsUZ0kl6MXSm4BaQgItD0VGlEKR3iq7gIaL7TjBvc=", + "owner": "ipetkov", + "repo": "crane", + "rev": "7d8ec2c71771937ab99790b45e6d9b93d15d9379", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1769524058, + "narHash": "sha256-zygdD6X1PcVNR2PsyK4ptzrVEiAdbMqLos7utrMDEWE=", + "owner": "nix-community", + "repo": "disko", + "rev": "71a3fc97d80881e91710fe721f1158d3b96ae14d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "disko", + "type": "github" + } + }, + "fenix": { + "inputs": { + "nixpkgs": [ + "continuwuity", + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1766299592, + "narHash": "sha256-7u+q5hexu2eAxL2VjhskHvaUKg+GexmelIR2ve9Nbb4=", + "owner": "nix-community", + "repo": "fenix", + "rev": "381579dee168d5ced412e2990e9637ecc7cf1c5d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1765121682, + "narHash": "sha256-4VBOP18BFeiPkyhy9o4ssBNQEvfvv1kXkasAYd0+rrA=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3", + "type": "github" + }, + "original": { + "owner": "edolstra", + "ref": "master", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1765835352, + "narHash": "sha256-XswHlK/Qtjasvhd1nOa1e8MgZ8GS//jBoTqWtrS1Giw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "a34fae9c08a15ad73f295041fec82323541400a9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1766070988, + "narHash": "sha256-G/WVghka6c4bAzMhTwT2vjLccg/awmHkdKSd2JrycLc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c6245e83d836d0433170a16eb185cefe0572f8b8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1765674936, + "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1771008912, + "narHash": "sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb+ZnAo5RzSxJg=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "a82ccc39b39b621151d6732718e3e250109076fa", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "continuwuity": "continuwuity", + "disko": "disko", + "nixpkgs": "nixpkgs_2", + "sops-nix": "sops-nix" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1766253897, + "narHash": "sha256-ChK07B1aOlJ4QzWXpJo+y8IGAxp1V9yQ2YloJ+RgHRw=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "765b7bdb432b3740f2d564afccfae831d5a972e4", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1771166946, + "narHash": "sha256-UFc4lfGBr+wJmwgDGJDn1cVD6DTr0/8TdronNUiyXlU=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "2d0cf89b4404529778bc82de7e42b5754e0fe4fa", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "continuwuity", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1766000401, + "narHash": "sha256-+cqN4PJz9y0JQXfAK5J1drd0U05D5fcAGhzhfVrDlsI=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "42d96e75aa56a3f70cab7e7dc4a32868db28e8fd", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..5318df1 --- /dev/null +++ b/flake.nix @@ -0,0 +1,90 @@ +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + sops-nix = { + url = "github:Mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + continuwuity = { + url = "git+https://forgejo.ellis.link/continuwuation/continuwuity"; + }; + }; + + outputs = + { + nixpkgs, + disko, + sops-nix, + continuwuity, + ... + }: + let + system = "x86_64-linux"; + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; + }; + in + { + nixosConfigurations.home-server = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { inherit continuwuity; }; + + modules = [ + disko.nixosModules.disko + sops-nix.nixosModules.sops + ( + { ... }: + { + nixpkgs = { + config.allowUnfree = true; + system = "x86_64-linux"; + }; + } + ) + ./hosts/homeserver/hardware-configuration.nix + ./common.nix + ./hosts/homeserver/configuration.nix + ./hosts/homeserver/setup.nix + ./services/website.nix + ./services/wireguard-inner.nix + ./services/matrix.nix + ./services/ergo.nix + ./services/akkoma.nix + ]; + }; + + nixosConfigurations.vps = nixpkgs.lib.nixosSystem { + inherit system; + + modules = [ + disko.nixosModules.disko + sops-nix.nixosModules.sops + ( + { ... }: + { + nixpkgs = { + config.allowUnfree = true; + system = "x86_64-linux"; + }; + } + ) + ./hosts/vps/hardware-configuration.nix + ./common.nix + ./hosts/vps/configuration.nix + ./hosts/vps/disko-config.nix + ./services/coturn.nix + ./services/wireguard-outer.nix + ]; + }; + + formatter.${system} = pkgs.nixfmt-tree; + }; +} diff --git a/hosts/homeserver/configuration.nix b/hosts/homeserver/configuration.nix new file mode 100644 index 0000000..434785a --- /dev/null +++ b/hosts/homeserver/configuration.nix @@ -0,0 +1,70 @@ +{ + modulesPath, + lib, + pkgs, + config, + ... +}: + +{ + boot.loader.systemd-boot = { + enable = true; + configurationLimit = 10; + }; + boot.loader.efi.canTouchEfiVariables = true; + + networking.hostName = "ellie-server"; + networking.useNetworkd = true; + + systemd.network.enable = true; + + hardware.graphics = { + enable = true; + }; + hardware.nvidia = { + package = config.boot.kernelPackages.nvidiaPackages.stable; + modesetting.enable = true; + open = false; + }; + + services.resolved.enable = true; + + services.openssh = { + openFirewall = false; + }; + + networking.nftables.enable = true; + networking.firewall = { + enable = true; + allowPing = true; + + checkReversePath = true; + rejectPackets = true; + allowedTCPPorts = [ ]; + interfaces."enp34s0".allowedTCPPorts = [ ]; + extraInputRules = '' + ip saddr 192.168.1.0/24 tcp dport {22, 8096, 8920, 3000, 8282, 9696, 8989, 7878, 80} accept + tcp dport {22, 8096, 8920, 3000, 8282, 9696, 8989, 7878, 80} drop + + ip saddr 192.168.1.0/24 udp dport 5353 accept + udp dport 5353 drop + ''; + }; + + users.groups.media = { }; + #users.users.radarr.extraGroups = [ "media" ]; + #users.users.sonarr.extraGroups = [ "media" ]; + #users.users.jellyfin.extraGroups = [ "media" ]; + + sops.age.keyFile = "/home/ellie/.config/sops/age/keys.txt"; + + environment.systemPackages = with pkgs; [ + git + vim + dropbear + age + sops + ]; + + system.stateVersion = "25.05"; +} diff --git a/hosts/homeserver/hardware-configuration.nix b/hosts/homeserver/hardware-configuration.nix new file mode 100644 index 0000000..a1db409 --- /dev/null +++ b/hosts/homeserver/hardware-configuration.nix @@ -0,0 +1,25 @@ +{ + config, + lib, + pkgs, + modulesPath, + ... +}: + +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ + "xhci-pci" + "ahci" + "usbhid" + ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/homeserver/setup.nix b/hosts/homeserver/setup.nix new file mode 100644 index 0000000..2b45fd3 --- /dev/null +++ b/hosts/homeserver/setup.nix @@ -0,0 +1,91 @@ +{ ... }: + +{ + boot.initrd.network = { + enable = true; + ssh = { + enable = true; + authorizedKeys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOv7i4ChPUm+DmELG6uRx0co4quhQ+h7QB4fgcxcC3qx contact@elliehigh.com" + ]; + shell = "/bin/cryptsetup-askpass"; + hostKeys = [ "/etc/initrd-ssh/ssh_host_ed25519_dropbear" ]; + }; + }; + + boot.initrd.preLVMCommands = '' + iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT + iptables -A INPUT -p tcp --dport 22 -j DROP + ''; + + fileSystems."/media" = { + device = "/dev/mapper/crypted"; + fsType = "btrfs"; + options = [ + "subvol=/media" + "compress=zstd" + "noatime" + ]; + }; + + disko.devices.disk.main = { + type = "disk"; + device = "/dev/sda"; + content = { + "type" = "gpt"; + partitions = { + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + luks = { + size = "100%"; + content = { + type = "luks"; + name = "crypted"; + settings = { + allowDiscards = true; + }; + content = { + type = "btrfs"; + # extraArgs = [ "-f" ]; + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/home" = { + mountpoint = "/home"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/jellyfin" = { + mountpoint = "/jellyfin"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/swap" = { + mountpoint = "/.swapvol"; + swap.swapfile.size = "36G"; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/hosts/vps/configuration.nix b/hosts/vps/configuration.nix new file mode 100644 index 0000000..034d422 --- /dev/null +++ b/hosts/vps/configuration.nix @@ -0,0 +1,7 @@ +{ ... }: + +{ + boot.loader.grub.enable = true; + + sops.age.keyFile = "/var/lib/sops-nix/key.txt"; +} diff --git a/hosts/vps/disko-config.nix b/hosts/vps/disko-config.nix new file mode 100644 index 0000000..4bc9b3d --- /dev/null +++ b/hosts/vps/disko-config.nix @@ -0,0 +1,39 @@ +{ ... }: + +{ + disko.devices = { + disk = { + main = { + type = "disk"; + device = "/dev/sda"; + content = { + type = "gpt"; + partitions = { + boot = { + size = "1M"; + type = "EF02"; + priority = 1; + }; + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + root = { + size = "100%"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/hosts/vps/hardware-configuration.nix b/hosts/vps/hardware-configuration.nix new file mode 100644 index 0000000..b3a836b --- /dev/null +++ b/hosts/vps/hardware-configuration.nix @@ -0,0 +1,8 @@ +{ modulesPath, lib, ... }: + +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + networking.useDHCP = lib.mkDefault true; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/services/akkoma.nix b/services/akkoma.nix new file mode 100644 index 0000000..7f8fe4d --- /dev/null +++ b/services/akkoma.nix @@ -0,0 +1,103 @@ +{ pkgs, ... }: + +let + inherit ((pkgs.formats.elixirConf { }).lib) mkRaw; + + mangane = pkgs.stdenv.mkDerivation rec { + pname = "mangane"; + version = "1.19.4"; + + src = pkgs.fetchzip { + url = "https://github.com/BDX-town/Mangane/releases/download/${version}/static.zip"; + hash = "sha256-Z+3rhqAlPX1sO0Lswky0rMe9pZmdFGWrckHDJnaCyQU="; + stripRoot = false; + }; + + installPhase = '' + runHook preInstall + + mkdir -p $out + cp -r dist/* $out/ + + runHook postInstall + ''; + }; +in +{ + networking.firewall.interfaces.wg0.allowedTCPPorts = [ 4000 ]; + + services.postgresql = { + enable = true; + }; + + services.akkoma = { + enable = true; + + frontends = { + primary = { + package = mangane; + name = "mangane"; + ref = "stable"; + }; + admin = { + package = pkgs.akkoma-admin-fe; + name = "admin-fe"; + ref = "stable"; + }; + }; + + config = { + ":pleroma" = { + "Pleroma.Web.Endpoint" = { + http = { + ip = "10.10.0.2"; + port = 4000; + }; + url = { + host = "akkoma.ellie.town"; + scheme = "https"; + port = 443; + }; + }; + "Pleroma.Upload" = { + base_url = "https://media.ellie.town"; + filters = map mkRaw [ + "Pleroma.Upload.Filter.Exiftool.StripMetadata" + ]; + }; + ":instance" = { + name = "ellie town"; + email = "wizzeh@protonmail.com"; + notify_email = "akkoma@ellie.town"; + description = "ellie's akkoma instance"; + registrations_open = false; + invites_enabled = false; + account_approval_required = false; + federating = true; + allow_relay = true; + languages = ["en"]; + public = false; + safe_dm_mentions = true; + healthcheck = true; + limit = 5000; + }; + ":configurable_from_database" = true; + ":http_security" = { + sts = true; + referrer_policy = "same-origin"; + }; + ":mrf" = { + policies = map mkRaw [ + "Pleroma.Web.ActivityPub.MRF.SimplePolicy" + "Pleroma.Web.ActivityPub.MRF.HellthreadPolicy" + "Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy" + ]; + }; + ":mrf_hellthread" = { + delist_threshold = 10; + reject_threshold = 20; + }; + }; + }; + }; +} diff --git a/services/coturn.nix b/services/coturn.nix new file mode 100644 index 0000000..18cd4e0 --- /dev/null +++ b/services/coturn.nix @@ -0,0 +1,72 @@ +{ config, pkgs, ... }: + +{ + sops.secrets."coturn/auth_secret_vps" = { + sopsFile = ./secrets/coturn_vps.yaml; + mode = "0400"; + owner = "turnserver"; + group = "turnserver"; + }; + + security.acme = { + acceptTerms = true; + defaults.email = "wizzeh@protonmail.com"; + certs."turn.ellie.town" = { + webroot = "/var/lib/acme/acme-challenges"; + }; + certs."ellie.town" = { }; + }; + + networking.firewall = { + allowedUDPPorts = [ + 3478 + 5349 + ]; + allowedTCPPorts = [ + 3478 + 5349 + 80 + 443 + ]; + allowedUDPPortRanges = [ + { + from = 49152; + to = 65535; + } + ]; + }; + + services.coturn = { + enable = true; + + realm = "turn.ellie.town"; + + use-auth-secret = true; + static-auth-secret-file = config.sops.secrets."coturn/auth_secret_vps".path; + + cert = "/var/lib/acme/turn.ellie.town/fullchain.pem"; + pkey = "/var/lib/acme/turn.ellie.town/key.pem"; + + listening-ips = [ + "0.0.0.0" + "::" + ]; + listening-port = 3478; + tls-listening-port = 5349; + + lt-cred-mech = true; + no-tcp-relay = true; + + min-port = 49152; + max-port = 65535; + }; + + services.nginx = { + enable = true; + virtualHosts."turn.ellie.town" = { + locations."/.well-known/acme-challenge/" = { + root = "/var/lib/acme/acme-challenges"; + }; + }; + }; +} diff --git a/services/ergo.nix b/services/ergo.nix new file mode 100644 index 0000000..8257cfc --- /dev/null +++ b/services/ergo.nix @@ -0,0 +1,113 @@ +{ lib, pkgs, config, ... }: + +let + settingsFormat = pkgs.formats.yaml { }; + ergoConfigFile = settingsFormat.generate "ircd.yaml" config.services.ergochat.settings; +in +{ + sops.secrets."ergo/oper_password_hash" = { + sopsFile = ./secrets/ergo.yaml; + mode = "0400"; + }; + + networking.firewall.interfaces.wg0.allowedTCPPorts = [ 6667 8097 ]; + + services.mysql = { + enable = true; + package = pkgs.mariadb; + ensureDatabases = [ "ergochat" ]; + ensureUsers = [ + { + name = "ergochat"; + ensurePermissions = { + "ergochat.*" = "ALL PRIVILEGES"; + }; + } + ]; + }; + + systemd.services.ergochat = { + after = [ "mysql.service" ]; + requires = [ "mysql.service" ]; + serviceConfig = { + SupplementaryGroups = [ "mysql" ]; + RuntimeDirectory = "ergochat"; + ExecStartPre = [ + # Run as root (+) to read our SOPS secret, then write the patched config + "+${pkgs.writeShellScript "ergochat-inject-secrets" '' + OPER_HASH=$(cat ${config.sops.secrets."ergo/oper_password_hash".path}) + sed "s|__OPER_PASSWORD_PLACEHOLDER__|$OPER_HASH|" ${ergoConfigFile} > /run/ergochat/ircd.yaml + chown ergochat:ergochat /run/ergochat/ircd.yaml + chmod 0400 /run/ergochat/ircd.yaml + ''}" + ]; + ExecStart = lib.mkForce "${pkgs.ergochat}/bin/ergo run --conf /run/ergochat/ircd.yaml"; + }; + }; + + services.ergochat = { + enable = true; + settings = { + network.name = "ellie.town"; + + server = { + name = "irc.ellie.town"; + enforce-utf8 = true; + listeners = lib.mkForce { + "10.10.0.2:6667" = { }; + "10.10.0.2:8097" = { websocket = true; }; + }; + }; + + accounts.registration.enabled = false; + accounts.nick-reservation.force-nick-equals-account = true; + accounts.nick-reservation.method = "strict"; + + datastore.mysql = { + enabled = true; + socket-path = "/run/mysqld/mysqld.sock"; + user = "ergochat"; + password = ""; + history-database = "ergochat"; + }; + + history.persistent = { + enabled = true; + unregistered-channels = false; + registered-channels = "opt-out"; + direct-messages = "opt-out"; + }; + + history.restrictions.expire-time = "0"; + + oper-classes = { + server-admin = { + title = "Server Admin"; + capabilities = [ + "rehash" + "accreg" + "chanreg" + "kill" + "ban" + "nofakelag" + "relaymsg" + "sajoin" + "samode" + "snomasks" + "history" + "defcon" + "massmessage" + ]; + }; + }; + + opers = { + ellie = { + class = "server-admin"; + whois-line = "is a server administrator"; + password = "__OPER_PASSWORD_PLACEHOLDER__"; + }; + }; + }; + }; +} diff --git a/services/matrix.nix b/services/matrix.nix new file mode 100644 index 0000000..9520c19 --- /dev/null +++ b/services/matrix.nix @@ -0,0 +1,33 @@ +{ config, continuwuity, ... }: + +{ + sops.secrets."coturn/auth_secret_home" = { + sopsFile = ./secrets/coturn_home.yaml; + mode = "0400"; + owner = "continuwuity"; + group = "continuwuity"; + }; + + networking.firewall.interfaces.wg0.allowedTCPPorts = [ 8008 ]; + + services.matrix-continuwuity = { + enable = true; + package = continuwuity.packages.x86_64-linux.default; + settings.global = { + server_name = "ellie.town"; + new_user_displayname_suffix = ""; + allow_registration = true; + + address = [ "10.10.0.2" ]; + port = [ 8008 ]; + + turn_uris = [ "turns:turn.ellie.town" ]; + turn_secret_file = config.sops.secrets."coturn/auth_secret_home".path; + + well_known = { + client = "https://matrix.ellie.town"; + server = "matrix.ellie.town:443"; + }; + }; + }; +} diff --git a/services/secrets/coturn_home.yaml b/services/secrets/coturn_home.yaml new file mode 100644 index 0000000..c1b0718 --- /dev/null +++ b/services/secrets/coturn_home.yaml @@ -0,0 +1,17 @@ +coturn: + auth_secret_home: ENC[AES256_GCM,data:ezWNA0NfHYBNq+pfwMBAl5I+g79Bx277NfLEi9irp+ey3EoZKwbRnfJ6gwExskUV8hiUWiCqj/Anbbd7XerF5w==,iv:neGLTFE8vdW6eALsOgrm5/nxqtx/+V1PY7xPG94BQN8=,tag:MXRiLPChtNvMKId/HX1fMA==,type:str] +sops: + age: + - recipient: age126v48dgev6pu3uhe7dtpdhax2yes2ff9u42ke2k2h97e90z8d4psedau7u + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArQnREeGtpTmx4WGtETThz + Nkk1bG9DUkJIWndhVzRkdGxFSUV0NmY2cW5nClg4L0g0T3NpT3U3YStOa3pPajVo + ZTNtTlk4WlpOc1Fra3I1RzRHWmRhbDgKLS0tIElBR1RyMjJxdjAyRm9rZFRDYzVq + V2RqU3VCTnY5UXIvMWRnTnV4MnpCeVUKQSqKoD0CpBYNklgUN400zXwzKCHKExMU + p83UFI1k/89VZCEJm/GJ+QrMl1fRj9zgNxakK4tFghEfNu4tkAub5A== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-09-01T00:22:01Z" + mac: ENC[AES256_GCM,data:3jh/mzPw2Q3Bsc1WYG9T/6VjxwpbP+meUkTZSqMbcIVgob22mAc0VWtRlAjK2183huqro5Od7O9+bOYUQ4s/TnaC8f79vi4aPAjgrFuAn0lCZLlF76d+1jMdBNzlXxdXfL5bkbBEYFnSzzkC+oRcRRW9iU83Nx1nJ4iZ6i1BZKU=,iv:mAmdvfBSXWmL+aZU+nn6IGEEKj1qByLZgeO7KGMcdWk=,tag:Ex3vSlAJdkh85xX1RP3fgg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.10.2 diff --git a/services/secrets/coturn_vps.yaml b/services/secrets/coturn_vps.yaml new file mode 100644 index 0000000..ce7980f --- /dev/null +++ b/services/secrets/coturn_vps.yaml @@ -0,0 +1,17 @@ +coturn: + auth_secret_vps: ENC[AES256_GCM,data:/kDgDOJ0FwmhcqDRVi8xGNrOK+4n38cPYr3KuKHXZkd7HdCUZSMY3f62BUZdAnIXaASFSQkmWEIjqT2LSCBz6Q==,iv:bRWwG6Yn319W/lxi9k1zSSJRBRNcRFxnpMs0EGXeKIc=,tag:+mPHNJTcYm07RWgSHdwEjA==,type:str] +sops: + age: + - recipient: age1856wmagg3dz4j07alwqnn6d75655t6wcs8glklyjyezhu5p875fq9sez4p + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxc05wa21aWmN1dGZWdWZO + VWg4WDJRMjZJYVZMZUxQSCtMdXRYdjloWmlBCmowdk1VY0pXbTluMHdQYlpwbG82 + bmZQZjRvZ1FKVklrc2xRcjBhSHNaeFkKLS0tIFA0VWdCdmxiTzU2R08reTA2WXNm + dUFXU0dLNFlvYXc5cWtKSGhveTErZ1EKGUZDVHYTiufhp3P2IKcBv0QUM9KremOr + vfG+83HK3LkydiOBUtYEuh/2Xv86dJ9Xs/be+HMbUwETNlzAHcyhNA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-09-01T00:22:26Z" + mac: ENC[AES256_GCM,data:QA7OTsClu+3GXbqxmfN53cUN778ZPfjX9ve+XYF1tjpyVcfSnLB9m0Dnb2xAI9AnZSRCPwqZq0sIAiUWzbVZ6TdgEMU+hEQq8immUg+ZchbKUkfQORgflcJtaRQI2ms6h7oHGPJLuSV3deUBqeRNx1Q31DpnsUcy94Qd/6JIHUg=,iv:33Kf+wt0gwf9wmyPQT2JyrmWPJ+u3jbexEJQ5j0paxk=,tag:g5ycy+E3I97XWecbnXMTEw==,type:str] + unencrypted_suffix: _unencrypted + version: 3.10.2 diff --git a/services/secrets/ergo.yaml b/services/secrets/ergo.yaml new file mode 100644 index 0000000..1b65c6f --- /dev/null +++ b/services/secrets/ergo.yaml @@ -0,0 +1,17 @@ +ergo: + oper_password_hash: ENC[AES256_GCM,data:9INtvkk0bbaaNw+uHqy7/ms9bEQ/AwQoP1WYKdJSS7HJDs5Ki0MhzgFFq2fCf6ovJdDs/cbwDSIjIJXZ,iv:NKUmdz6o5zbKWbNOpiqtM3OaU/tmMpYmgEQlqtNDIsY=,tag:n822gtnHaH/ffL3BvBIX6w==,type:str] +sops: + age: + - recipient: age126v48dgev6pu3uhe7dtpdhax2yes2ff9u42ke2k2h97e90z8d4psedau7u + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwT0RyeVlwYjRtbnRmOHZO + WE8wRXpYS2pQNlhUSUJoS0ZOb0NHajlDZ2tNCkNobnNWTDVCd2xWblNENUNiOWRM + c2svWEdkbUtKSkVOV0MvK2l1MjB1Y0EKLS0tIDhNaFBLZ3JnY2JBY0pjc0RSd1M5 + KzYxaXVacEh2MmdNbnhPMEtkSUJ0UHcKfLGMEsdGDcmAnXWK7aGSMr6ZjsQQiT8l + PjTGUyVAWBVGaQEaV33VT7y4rrns+8PmEzfMKl2y12iP6R7Jm9AntA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-02-10T23:31:43Z" + mac: ENC[AES256_GCM,data:l2C3HPIn5NiidEgS38vsxxkJRtij6mTiqoSQGYaaLc7tKAbJnppLwO7/Ps/3ZwcLVe+Se7/5sEel2u0aXO9nbhs4e0T83x0+wOOW4464tdN66gn3mGcNslWS7LzMl4JbL57Qx6WC9OW1xg3lw67FcPte/j7KWO3xGqG6K5Bqrjo=,iv:nE8ez8udhu0IVg7CGM2/pPxPn4gehWwxbXXwPc8TI0E=,tag:bScTdwfH6edsQOTEgyl6fg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/services/secrets/wireguard_home.yaml b/services/secrets/wireguard_home.yaml new file mode 100644 index 0000000..3b6d066 --- /dev/null +++ b/services/secrets/wireguard_home.yaml @@ -0,0 +1,17 @@ +wireguard: + private_key: ENC[AES256_GCM,data:2UFwy9hqFIZ61pminFni+w0uJJlKL9vJz4Kh81Z+NtH8K3sgOy5ZVsfH6+0=,iv:CPq9xVzSxo9A7LfzEpyTAthqRQ26aeOOEEOt1izIA9E=,tag:X5HdQD7TnTdmGc227HrJfQ==,type:str] +sops: + age: + - recipient: age126v48dgev6pu3uhe7dtpdhax2yes2ff9u42ke2k2h97e90z8d4psedau7u + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhOW1HbmUrYmdwQ21GQ3FP + UWM0cEFqcDlnQ2U3WldWRDhIOVpMM2tQSlJZCmp0dldJd3pxd0luRitmWk1hVk5w + SWZNZVdrRnV0MEtYSWtYb2xramlOczAKLS0tIDBCTVJ5clozUzZ4dDBXU3dxVG5n + bm9EeXFQNFZQT0tvT05PeXB3bGNxLzQKDXcd3unCZ0SgBrYFehz38ppHFF8T5QqH + TcZMPWHthvGt0OrY6uis/aTBZOBSv/k4sAocTN/e+vR0v9kHMcSw3A== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-02-10T23:31:35Z" + mac: ENC[AES256_GCM,data:XkhjxTIQJBZgSVyeQcx9J3BLux/4+JPnDjZyaL4utZWWP+mkzNmD4UNU/6YpWahouix/ftq9bT2ISV/m5b9+ps9eMHjTLGGjnPB0O4gJx0sEYqY1lOgW51NnqXcogvQ6JEMkO03C/0zyXpn+GEf2Yq0sEnh2XGLTsoojGgS+CTY=,iv:rZPBJnJgOG9l1yWZ2rdzweBda6vwa06P1kkGOlDBVPY=,tag:1QjaoljyCF92YMQB4ysYpQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/services/secrets/wireguard_vps.yaml b/services/secrets/wireguard_vps.yaml new file mode 100644 index 0000000..f6e6059 --- /dev/null +++ b/services/secrets/wireguard_vps.yaml @@ -0,0 +1,17 @@ +wireguard: + private_key: ENC[AES256_GCM,data:SY/y0Lo2c3luFgTGMzkmFUuDk/JXD0exrZpIglfvdRto0lci0B7k/iVQv8Y=,iv:2lUzaKj0eEZVbRORd9BuPLK5thX8kxEszfsknBNSP2E=,tag:yABpH9Opuwu5MmtygmMpwA==,type:str] +sops: + age: + - recipient: age1856wmagg3dz4j07alwqnn6d75655t6wcs8glklyjyezhu5p875fq9sez4p + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZYW1LR09adjllcy9OMzVm + T2lGdjlRWU53KyttaElPeGtQY1ZZRWRpOGlRCkp6ckdkSnAwazQwM3NQV1JVOHJp + OTZRWGYyWnovanljbG5FRGI3ZllQckEKLS0tIFR2ZW14QmxDcElWSXAzSzNXS1BS + eW9jQVdEUFpsR1hDRXR0dDhrVFo4VjAKiOPabz4+pb5lwxh0gAhr35cavG9aS/qa + xUndQM6xGfZQwgoOt5LX1Xlo5HBJifTpdUPvMxgPKwHbUyTQY5lKNQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-02-10T23:31:40Z" + mac: ENC[AES256_GCM,data:Z/qrV4V4ZaIhzrIC/SDnCdRFnQEbaYn/zZ/PVhcVkA8qd5WHLHLZMRjOTLPstMo8ll88ua00e6KShlZJLsi1/bSG4WKxTz2Yv/TkGRTD4KE25LmqFLe/70YM1f7SC/QvmlYecVCCWpwXB6rRprt38X2Fzez5AeReZdkdo/IuH1w=,iv:38GOJdQw/9vJQPKHkK/U1HBixqQfo8m0l4HwYOKkm4s=,tag:9Ci8yglwFLQz1RXoXCCN6A==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/services/website.nix b/services/website.nix new file mode 100644 index 0000000..5d730f4 --- /dev/null +++ b/services/website.nix @@ -0,0 +1,31 @@ +{ pkgs, ... }: + +let + site = pkgs.copyPathToStore ../data/service-directory; +in +{ + services.avahi = { + enable = true; + nssmdns4 = true; + nssmdns6 = true; + + publish = { + enable = true; + addresses = true; + domain = true; + workstation = true; + }; + }; + + services.nginx = { + enable = true; + + virtualHosts."service-directory" = { + root = site; + + locations."/" = { + index = "index.html"; + }; + }; + }; +} diff --git a/services/wireguard-inner.nix b/services/wireguard-inner.nix new file mode 100644 index 0000000..bad611f --- /dev/null +++ b/services/wireguard-inner.nix @@ -0,0 +1,24 @@ +{ config, ... }: + +{ + sops.secrets."wireguard/private_key" = { + sopsFile = ./secrets/wireguard_home.yaml; + mode = "0400"; + }; + + networking.firewall.allowedUDPPorts = [ 51820 ]; + + networking.wireguard.interfaces."wg0" = { + ips = [ "10.10.0.2/24" ]; + privateKeyFile = config.sops.secrets."wireguard/private_key".path; + listenPort = 51820; + peers = [ + { + publicKey = "9itF3RfEP/DhK1C1288njiCQg0AMjjvRsWDYGyNj0ns="; + endpoint = "23.88.105.213:51820"; + allowedIPs = [ "10.10.0.1/32" ]; + persistentKeepalive = 25; + } + ]; + }; +} diff --git a/services/wireguard-outer.nix b/services/wireguard-outer.nix new file mode 100644 index 0000000..4d88630 --- /dev/null +++ b/services/wireguard-outer.nix @@ -0,0 +1,108 @@ +{ lib, pkgs, config, ... }: + +{ + sops.secrets."wireguard/private_key" = { + sopsFile = ./secrets/wireguard_vps.yaml; + mode = "0400"; + }; + + networking.firewall.allowedTCPPorts = [ + 80 + 443 + 6697 + ]; + networking.firewall.allowedUDPPorts = [ 51820 ]; + + networking.wireguard.interfaces."wg0" = { + ips = [ "10.10.0.1/24" ]; + listenPort = 51820; + privateKeyFile = config.sops.secrets."wireguard/private_key".path; + + peers = [ + { + publicKey = "s2plHABMTF83iqrCHlQ+o5ieJSAfudx3upm3v77y1DI="; + allowedIPs = [ "10.10.0.2/32" ]; + } + ]; + }; + + services.nginx = { + enable = true; + + recommendedGzipSettings = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + + defaultListen = [ + { addr = "0.0.0.0"; } + { addr = "[::]"; } + ]; + + virtualHosts."matrix.ellie.town" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://10.10.0.2:8008"; + }; + }; + + # virtualHosts."akkoma.ellie.town" = { + # enableACME = true; + # forceSSL = true; + # locations."/" = { + # proxyPass = "http://10.10.0.2:4000"; + # proxyWebsockets = true; + # extraConfig = '' + # client_max_body_size 16m; + # ''; + # }; + # }; + + # virtualHosts."media.ellie.town" = { + # enableACME = true; + # forceSSL = true; + # locations."/" = { + # proxyPass = "http://10.10.0.2:4000"; + # extraConfig = '' + # client_max_body_size 16m; + # ''; + # }; + # }; + + virtualHosts."irc.ellie.town" = { + enableACME = true; + forceSSL = true; + }; + + streamConfig = '' + upstream ergo { + server 10.10.0.2:6667; + } + server { + listen 6697 ssl; + ssl_certificate /var/lib/acme/irc.ellie.town/fullchain.pem; + ssl_certificate_key /var/lib/acme/irc.ellie.town/key.pem; + proxy_pass ergo; + } + ''; + + virtualHosts."ellie.town" = { + enableACME = true; + forceSSL = true; + locations."= /.well-known/matrix/server".extraConfig = '' + default_type application/json; + add_header Access-Control-Allow-Origin *; + return 200 '{"m.server":"matrix.ellie.town:443"}';''; + + locations."= /.well-known/matrix/client".extraConfig = '' + default_type application/json; + add_header Access-Control-Allow-Origin *; + return 200 '{"m.homeserver":{"base_url":"https://matrix.ellie.town"}}';''; + }; + }; + + security.acme = { + acceptTerms = true; + defaults.email = "wizzeh@protonmail.com"; + }; +}