Initial commit
Some checks failed
CI / check (push) Has been cancelled
CI / ida (push) Has been cancelled
CI / cpt (push) Has been cancelled
CI / build-nixos (ena) (push) Has been cancelled
CI / build-nixos (hako) (push) Has been cancelled
CI / build-nixos (kazusa) (push) Has been cancelled
CI / build-nixos (mizuki) (push) Has been cancelled

This commit is contained in:
암냥 2026-07-03 16:53:49 +09:00
commit 70284509f3
No known key found for this signature in database
144 changed files with 7061 additions and 0 deletions

View file

@ -0,0 +1,5 @@
creation_rules:
- path_regex: secrets/.*\.ya?ml$
age:
- age1mgels4hjl7l07gcnt72g86kvhrvd82fha9kuvlp46mpks7unrpmqvy959u # mizuki
- age1dcvh6q9953es9fvt8rq8rdgcktlt64asn2tf2y3vmyz0gntxzynqg2xgzk # hako

View file

@ -0,0 +1,43 @@
{ pkgs, inputs, ... }:
{
imports = [
./hardware-configuration.nix
"${inputs.self}/modules/nixos/base"
"${inputs.self}/modules/nixos/features/boot.nix"
"${inputs.self}/modules/nixos/features/ssh.nix"
"${inputs.self}/modules/nixos/features/docker.nix"
];
# 1. 크론 설정
services.cron = {
enable = true;
systemCronJobs = [
"0 1 * * * imnyang printf '\\n%s : ' \"$(date)\" >> /home/imnyang/codelounge.log && /home/imnyang/codelounge.sh >> /home/imnyang/codelounge.log"
];
};
services.qemuGuest.enable = true;
# 2. 사용자 SSH 키 등록
users.users.imnyang.openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOHP3Z+AYrRh9f8TYyqChKfeyNm3lOe0F75AwRHTTaxD imnyang@kazusa"
];
environment.systemPackages = with pkgs; [
eza
neovim
nil
nixd
];
programs.git.config = {
safe.directory = "*";
};
nix.settings.require-sigs = false;
networking.firewall.enable = false;
networking.hostName = "hako";
system.stateVersion = "26.05";
}

View file

@ -0,0 +1,32 @@
{
inputs,
overlays,
}:
let
inherit (inputs) nixpkgs home-manager sops-nix;
in
nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
sops-nix.nixosModules.sops
./services/forgejo.nix
./services/immich.nix
./services/attic.nix
./services/postgresql.nix
./services/nc.nix
./configuration.nix
./hardware-configuration.nix
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.extraSpecialArgs = { inherit inputs; };
home-manager.users.imnyang = import ./home.nix;
}
];
specialArgs = {
inherit inputs;
inherit overlays;
};
}

View file

@ -0,0 +1,51 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to configuration.nix instead.
{ lib, modulesPath, ... }:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [
"uhci_hcd"
"ehci_pci"
"ahci"
"virtio_pci"
"virtio_scsi"
"sd_mod"
"sr_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/d65b2c3a-c630-4a07-bcf3-ec1b728129c0";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/67DC-8A41";
fsType = "vfat";
options = [
"fmask=0077"
"dmask=0077"
];
};
fileSystems."/mnt/data" = {
device = "/dev/disk/by-uuid/edc0420b-8bec-438d-856d-bb345238e735";
fsType = "ext4";
};
fileSystems."/mnt/attic" = {
device = "/dev/disk/by-uuid/f45e0247-d2eb-4150-8116-e8d257c01aac";
fsType = "ext4";
};
swapDevices = [ ];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

View file

@ -0,0 +1,66 @@
{
pkgs,
inputs,
...
}:
let
nr = import "${inputs.self}/modules/nixos/features/packages/nr.nix" { inherit pkgs; };
nrr = import "${inputs.self}/modules/nixos/features/packages/nrr.nix" { inherit pkgs; };
in
{
home.stateVersion = "26.05";
home.username = "imnyang";
home.homeDirectory = "/home/imnyang";
home.packages = [
nr
nrr
];
home.sessionVariables = {
EDITOR = "nano";
VISUAL = "nano";
};
programs.fish = {
enable = true;
shellAliases = {
".." = "cd ..";
"..." = "cd ../..";
ls = "eza";
ll = "eza -l";
la = "eza -a";
lla = "eza -la";
rebuild = "sudo nixos-rebuild switch --flake .#hako";
update = "nix flake update";
clean = "sudo nix-collect-garbage -d";
};
interactiveShellInit = ''
set -g fish_greeting ""
set -g fish_color_command blue
set -g fish_color_error red
set -g fish_color_param cyan
'';
functions = {
fish_prompt = ''
set_color purple
echo -n (whoami)
set_color normal
echo -n "@"
set_color green
echo -n (hostname)
set_color normal
echo -n ":"
set_color blue
echo -n (prompt_pwd)
set_color normal
echo -n " > "
'';
};
};
}

View file

@ -0,0 +1,29 @@
forgejo:
server_lfs_jwt_secret: ENC[AES256_GCM,data:mBK+mUvGTlSPLEifBahWuKMWMAlMNXmgA5jdGl+RElA4+msogvHB1g7V1g==,iv:YDc7ZgDPP0st0hYLJGbsapkVAG2L372AXFGwax9y+hc=,tag:4rfv0tfvgk/octiBkFnD6Q==,type:str]
security_internal_token: ENC[AES256_GCM,data:zmEnyWTmZrcUQTu7zu/QaVGzMzNvzkWYpRsCygD/SKzQe+kHG/FGr8rPwUQGIoUvdc2FcAykfsFZtnBwDgIeEonG+jdGYF41yIrh18hAXG00jn+K5fhq9x2IAGJz6qtvM7usiw2aCLLF,iv:DkkKZl9KKbtOKk1OHxoQmBMhN91NGHKAijcaJVxHXgM=,tag:FJkWGty/yAUJQaZB6RNcuQ==,type:str]
oauth2_jwt_secret: ENC[AES256_GCM,data:SpTNvHaxR1Ai8hdoTVcl3HVm5ZwA4oNoXUD5Cw8J5cy63ZLOZMX6tCBLCg==,iv:cm0uqiaizsEqPWD6b1cusME6LGXhSEhmd2bcdf/kxUM=,tag:iYpIDsIRd6ahJdL2RgjPTw==,type:str]
mailer_passwd: ENC[AES256_GCM,data:FXQN7xvjtR2MJGp/DkiF6jyglztjZ7vKxmHB7YWux0E=,iv:G5DSbqeKykq1HjQfWwHdLeS3bHkCbjsgH57Nfaaev84=,tag:8Q1RC3f8wNjUPm1nL+J4IQ==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDQ1hzM3BEUEdqaUlnckhK
VXhHSzI1SmxBUCsxbU1FZmZhTkppa2xCbzNnCjhjc05oTFdnbjByR0N6eklpZTVh
dXNid290ZWRqNStKdkhiczdaQ1FaZlUKLS0tIEkvRmN5UTQ0dXBRRDB3YkR5UklL
OUh4NVZER0FOcGtZMksrdzk2c2ZHVHcKgkrUSWjK2+44+svbVSzHn31QPieTtXb2
7/A689V4CgGO+eoECxaKepEbWmXb2iCuLa2fNhUQIv1veKq/ga1aNA==
-----END AGE ENCRYPTED FILE-----
recipient: age1mgels4hjl7l07gcnt72g86kvhrvd82fha9kuvlp46mpks7unrpmqvy959u
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVbjNtWjBRVFFEdGdKbXBC
RWo1UngvVEpqNW92MGlHZHI4dG9pWGdaS1VNCjhzakYyNUwzaWM3WjY4cHNvUW9t
N3hsTlpkV3BEQXZSSGh4MGlKVkNuWDAKLS0tIGFDcFNuQlBnaFN6SWs2K1dDVlVW
M1Z4VFdsWlhOTEZxR256a0xqa1dVcUkKrL52dR1o186VXcxp3ap5cyZUh5pjgQPC
TmBnn6qSneJHztKUBTz5PBsesdDrNX4m/UYahb7feRO70dQvGxeo0A==
-----END AGE ENCRYPTED FILE-----
recipient: age1dcvh6q9953es9fvt8rq8rdgcktlt64asn2tf2y3vmyz0gntxzynqg2xgzk
lastmodified: "2026-05-25T05:46:33Z"
mac: ENC[AES256_GCM,data:GY6EpM2BwOHFHtOGuQ6qHepH94xhEMnQDxshl+aGhIVGCi+34YW6WjFtBcFFLcmxSuMbEx8w2jK0T6PE7cyAwnphkz/G0qx2AAn836SN0wlfyY3Ni1czcdcuc9s2QdlBc9VhVU8s70fnso2tZxQsyM5wplgparJAJfxNycLFr9g=,iv:sHxJZm6waB+PW76rs6H26ffelsty1KAQFzwgbLv7Qls=,tag:Ofir+9DXvlSU/RtG4ivNCQ==,type:str]
unencrypted_suffix: _unencrypted
version: 3.13.1

View file

@ -0,0 +1,28 @@
immich:
oauth2:
client-id: ENC[AES256_GCM,data:HY69lAGt3g7JqRG1EzmWXZpSCGSPwm2vqdIU2RkhXdon3C4JeXb9fw==,iv:Ew2r4kOx6cP2uZD6btyPmFpT0SOkJFM2WeT/fq6zaLc=,tag:aZimoy63KoR2hwRQUOGPRw==,type:str]
client-secret: ENC[AES256_GCM,data:U9YE9DnsNbLU2bTZWRWjEWFCCl0b2GS7IWfg2ooGrbmSi/A9DFzGSxvUdJQHKVbsX3bFCDd55citwJRVUQDiFSNSX78npQSzRJ8Jj9VSYOmHsO376I/Wm8sLQfvApcvltwaNV1rzfQyKGaBqGkFb58AbG55h/6bObqWWOl6+g5I=,iv:/odWOJedazBbMYsNwNVLPbBdAJb8f73brz+PUpaNwDg=,tag:VdY5zAHbPkYBRrmZyGSSTg==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJOXo0RkpUekJZN3lhaU1S
ZWNDaUdud0EzbUhIbU9lYVRyQ3pQazRrMlZRCjdPMDZDNVpST3p2VHJ0Tmg2WUZP
eWF4R0dBaW1zRmJNdjVaVWV3UjgvL2MKLS0tIFJQQ1pMQzB5aU9wNmYxYktJdHU5
NWV6Q0NuWUwrMTZ5RE9PV3ZVMTkvK00KJaPJojaZGx8NNfgxO4Q6AUbbCRGxEHAz
QX4zycDizXnL3kWmF1T66Cew6EuhHZSl5ZYFYUilHjq8r0lx2RuCOg==
-----END AGE ENCRYPTED FILE-----
recipient: age1mgels4hjl7l07gcnt72g86kvhrvd82fha9kuvlp46mpks7unrpmqvy959u
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvTjFKQlZVUCtNLzUzUGRO
TjlDYjQ3dmxEd0ZUcGZpTk5wU3kzWXVpRUY4CnI1bjBubU91dWJmSjlUOFlyYkNm
MkxIZTZ5SmFuT1ZqT3dkYVZQcmFWZk0KLS0tIGhPYzZpNEkwcTJzQUpwdndNNmlN
a05vWkZLeEpmaWpka1Z6RXRUdFRRZ3cKQBfF4IYpt5RO9+XmooTI58cSmkqwnQmN
aSt73yBzGVPJulggcYuDsy/k8lfPhPseKVvuR8p/jzwKG6iNGNm86g==
-----END AGE ENCRYPTED FILE-----
recipient: age1dcvh6q9953es9fvt8rq8rdgcktlt64asn2tf2y3vmyz0gntxzynqg2xgzk
lastmodified: "2026-04-02T15:08:04Z"
mac: ENC[AES256_GCM,data:uDCTiO0f3Ogj+dMNGoFIPptCBgLbN0goh/KDiLqCJXvLVkNCqpJYK0V46CmwQnSNyrth2jEQhnx0TBF2JSKfyU+UNpgC9zcLsuUznYQiBl+s2cT2nbApcLgJBSxWcvCpEEGqUp71jw8ajaUwjaLGdHePNsn4K3rAOL0j1Yythxo=,iv:bx3ctA+6hEeq0BHJqf4BQBJhihh3uGlS7NwalmXJgXg=,tag:sM4wAT0qfUZMI7gE0b++3g==,type:str]
unencrypted_suffix: _unencrypted
version: 3.12.2

View file

@ -0,0 +1,26 @@
google:
api-key: ENC[AES256_GCM,data:1BdTd7JyoeZ/U/6kWKAcgYeRokjR/mD0OLrmJrp7fXTE6rI4YT/RdQZauAA+xiGLBELdVCo=,iv:s9ms0pr7iwQW7HxhlpQSHCRc9pWlbnY3MH6iKxnoFYg=,tag:uWTmkMWikoFVGCeyG6fOrQ==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0U1FuMjg4Q0llaU1yUCtX
SG5aUnVoUGRaRG9WSGNKQlFmNFdtS1JOdDFVCjlDbHVnUWlCWWtQcXJjSExTL3JT
cHM3RTRNK1BVZzdXZ1g0bFdYcnltU2cKLS0tIHpHQmRqTndLNUJWYnR4TVVHOGJ0
ZExCNlphODcrbGdxa0tYNGxQS1lJNDQKes+ZdaWVPmAHxsomvBhGSha58T0vOTvN
T14s3k+nAtyOq0oJ71AuzZVsWS/1ubMFvtOAnVTsCae1BZ5AAGTU0A==
-----END AGE ENCRYPTED FILE-----
recipient: age1mgels4hjl7l07gcnt72g86kvhrvd82fha9kuvlp46mpks7unrpmqvy959u
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMQXNaR0dldTBMa3YrK1ZE
K1NhclpZblJzdVFGU1hLVHRtSFR1bmhBeFZjCmRyNXNRVGxrYUZEWGpQR2gycHd2
TGJUVmpVTjcvaFBtZFpBTjNqVHVTcHMKLS0tIDUrYVI4LytnN0tCM3RZdzMwekFi
NnJkRGc5VUd3WUNXODRLZ2dkbWZ0QlUKPkU0P/fuGIVRwGgdwkxxEoeXTM7BBL7m
29fTZi7bgVajYoaA52CIjGFYnzt6phqlvjMC6PFlGG23ifaYEKlgQQ==
-----END AGE ENCRYPTED FILE-----
recipient: age1dcvh6q9953es9fvt8rq8rdgcktlt64asn2tf2y3vmyz0gntxzynqg2xgzk
lastmodified: "2026-06-25T09:28:44Z"
mac: ENC[AES256_GCM,data:uZWZQ4u5gqfTnNp9uVqfXOqwAgaTL4hT5a/A5d+o0D6MCpM/f80hnaWBynFryI1NlPUFjQ6gyGBTFxkEeUnhB/pQit6XBE0Ex0F+UKy5U8QAcPhN2/5if/Upd9l3yiLaul+kH49FkkHwRhpA++GXFUr66stsHYPMFXM2vQAJQgQ=,iv:AwE69cX+jmrUz/pJqAIsS9Vhl2rd947xAViQYz6gkSA=,tag:qg4jpYHTYjBkt9vfER+YkA==,type:str]
unencrypted_suffix: _unencrypted
version: 3.13.1

View file

@ -0,0 +1,21 @@
{
services.atticd = {
enable = true;
# Replace with absolute path to your environment file
environmentFile = "/etc/atticd.env";
settings = {
listen = "[::]:8080";
jwt = { };
database.url = "postgresql:///attic";
storage = {
type = "local";
path = "/mnt/attic";
};
};
};
}

View file

@ -0,0 +1,130 @@
{
config,
lib,
pkgs,
...
}:
{
sops = {
defaultSopsFile = ../secrets/forgejo.yaml;
validateSopsFiles = false;
age = {
keyFile = "/var/lib/sops-nix/key.txt";
generateKey = true;
};
secrets = {
"forgejo/server_lfs_jwt_secret" = {
owner = "forgejo";
group = "forgejo";
restartUnits = [ "forgejo.service" ];
};
"forgejo/security_internal_token" = {
owner = "forgejo";
group = "forgejo";
restartUnits = [ "forgejo.service" ];
};
"forgejo/oauth2_jwt_secret" = {
owner = "forgejo";
group = "forgejo";
restartUnits = [ "forgejo.service" ];
};
"forgejo/mailer_passwd" = {
owner = "forgejo";
group = "forgejo";
restartUnits = [ "forgejo.service" ];
};
};
};
services.forgejo = {
enable = true;
package = pkgs.forgejo;
database = {
type = "postgres";
createDatabase = true;
host = "/run/postgresql/";
name = "forgejo";
user = "forgejo";
};
settings = {
DEFAULT = {
APP_NAME = "git.mizuki.guru";
APP_SLOGAN = "with 🎀";
RUN_MODE = "prod";
};
federation = {
ENABLED = true;
};
server = {
DOMAIN = "git.mizuki.guru";
SSH_DOMAIN = "mizuki.guru";
HTTP_PORT = 3000;
ROOT_URL = "https://git.mizuki.guru/";
DISABLE_SSH = false;
SSH_PORT = 22;
LFS_START_SERVER = true;
OFFLINE_MODE = false;
};
security = {
INSTALL_LOCK = true;
PASSWORD_HASH_ALGO = "pbkdf2_hi";
};
service = {
REGISTER_EMAIL_CONFIRM = true;
ENABLE_NOTIFY_MAIL = true;
DISABLE_REGISTRATION = false;
ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
ENABLE_CAPTCHA = false;
REQUIRE_SIGNIN_VIEW = false;
DEFAULT_KEEP_EMAIL_PRIVATE = false;
DEFAULT_ALLOW_CREATE_ORGANIZATION = true;
DEFAULT_ENABLE_TIMETRACKING = true;
NO_REPLY_ADDRESS = "noreply.relay.imnya.ng";
};
mailer = {
ENABLED = true;
SMTP_ADDR = "mail.mizuki.guru";
SMTP_PORT = 587;
FROM = "systemmail@mizuki.guru";
USER = "systemmail@mizuki.guru";
};
oauth2 = {
ENABLED = true;
};
actions = {
ENABLED = true;
};
ui = {
THEMES = "dark,light,auto,forgejo-auto,forgejo-light,forgejo-dark";
DEFAULT_THEME = "auto";
};
repository = {
ROOT = "/var/lib/forgejo/repositories";
};
"repository.pull-request".DEFAULT_MERGE_STYLE = "merge";
"repository.signing".DEFAULT_TRUST_MODEL = "committer";
"cron.update_checker".ENABLED = true;
session.PROVIDER = "file";
oauth2_client.ENABLE_AUTO_REGISTRATION = true;
};
secrets = {
server.LFS_JWT_SECRET = lib.mkForce config.sops.secrets."forgejo/server_lfs_jwt_secret".path;
security.INTERNAL_TOKEN = lib.mkForce config.sops.secrets."forgejo/security_internal_token".path;
oauth2.JWT_SECRET = lib.mkForce config.sops.secrets."forgejo/oauth2_jwt_secret".path;
mailer.PASSWD = lib.mkForce config.sops.secrets."forgejo/mailer_passwd".path;
};
};
}

View file

@ -0,0 +1,37 @@
{ config, ... }:
let
immichSecret = key: {
sopsFile = ../secrets/immich.yaml;
inherit key;
owner = "immich";
};
in
{
sops.secrets."immich/oauth2/client-id" = immichSecret "immich/oauth2/client-id";
sops.secrets."immich/oauth2/client-secret" = immichSecret "immich/oauth2/client-secret";
services.immich = {
enable = true;
host = "0.0.0.0";
port = 10040;
mediaLocation = "/mnt/data/immich/media";
openFirewall = true;
machine-learning.enable = false;
settings = {
server.externalDomain = "https://i.mizuki.guru";
machineLearning = {
enabled = false;
};
oauth = {
enabled = true;
issuerUrl = "https://auth.mizuki.guru/application/o/immich/.well-known/openid-configuration";
clientId._secret = config.sops.secrets."immich/oauth2/client-id".path;
clientSecret._secret = config.sops.secrets."immich/oauth2/client-secret".path;
scope = "openid email profile";
buttonText = "Login with mizuki";
};
};
};
}

View file

@ -0,0 +1,63 @@
{
pkgs,
inputs,
config,
...
}:
let
ncSecret = key: {
sopsFile = ../secrets/nc.yaml;
inherit key;
owner = "mizuki-nc";
group = "mizuki-nc";
mode = "0400";
};
in
{
users.users.mizuki-nc = {
isSystemUser = true;
group = "mizuki-nc";
};
users.groups.mizuki-nc = { };
sops.secrets."google/api-key" = ncSecret "google/api-key";
systemd.services.mizuki-nc = {
description = "mizuki.guru";
wantedBy = [ "multi-user.target" ];
preStart = ''
set -eu
umask 077
rm -f /var/lib/mizuki-nc/config.toml
cat > /tmp/mizuki-nc-config.toml <<EOF
[google]
api-key = "$(cat ${config.sops.secrets."google/api-key".path})"
EOF
install -o mizuki-nc -g mizuki-nc -m 0400 \
/tmp/mizuki-nc-config.toml \
/var/lib/mizuki-nc/config.toml
rm -f /tmp/mizuki-nc-config.toml
'';
serviceConfig = {
User = "mizuki-nc";
Group = "mizuki-nc";
StateDirectory = "mizuki-nc";
StateDirectoryMode = "0750";
WorkingDirectory = "/var/lib/mizuki-nc";
ExecStart = "${inputs.mizuki-nc.packages.${pkgs.system}.default}/bin/mizuki-nc";
Restart = "always";
RestartSec = 3;
};
};
}

View file

@ -0,0 +1,16 @@
{ pkgs, ... }: {
services.postgresql = {
enable = true;
package = pkgs.postgresql_17.withPackages (ps: with ps; [
pgvector
vectorchord
]);
ensureDatabases = [ "attic" "atticd" ];
ensureUsers = [
{
name = "atticd";
ensureDBOwnership = true;
}
];
};
}