first commit

This commit is contained in:
Stuce 2025-11-13 16:01:47 +01:00
commit e46461326d
10 changed files with 632 additions and 0 deletions

118
authelia.nix Normal file
View file

@ -0,0 +1,118 @@
let host = "stuce.ch";
in {
services.authelia.instances."main" = {
enable = true;
secrets = {
oidcHmacSecretFile = "/var/lib/authelia-main/hmac";
oidcIssuerPrivateKeyFile = "/var/lib/authelia-main/rsa.2048.key";
jwtSecretFile = "/var/lib/authelia-main/jwtSecret";
storageEncryptionKeyFile =
"/var/lib/authelia-main/storageEncryptionKeyFile";
};
environmentVariables = {
AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE =
"/var/lib/authelia-main/ldap_password";
AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE =
"/var/lib/authelia-main/smtp_password";
};
settings = {
authentication_backend = {
password_reset = { disable = false; };
refresh_interval = "1m";
ldap = {
implementation = "lldap";
address = "ldap://localhost:3890";
base_dn = "dc=stuce,dc=ch";
user = "uid=bind_user,ou=people,dc=stuce,dc=ch";
additional_users_dn = "ou=people";
};
};
storage = { local = { path = "/var/lib/authelia-main/db.sqlite3"; }; };
session = {
cookies = [{
domain = "${host}";
authelia_url = "https://auth.${host}";
default_redirection_url = "https://${host}";
}];
};
notifier = {
# disable_startup_check = false;
# filesystem = { filename = "/var/lib/authelia-main/notification.txt"; };
smtp = {
address = "submissions://mail.infomaniak.com:465";
username = "no-reply@stuce.ch";
sender = "no-reply@stuce.ch";
};
};
identity_providers = {
oidc = {
jwks = { };
clients = [{
client_id =
"uZzbagYr2RZqyVFsOZ23XJktE9tjllwuMnxiicfT5Ykcx6pX9JZDXlYahdg.DRq5guobvv0k";
client_name = "Forgejo";
# TODO: find a way to remove this secret from here
client_secret =
"$pbkdf2-sha512$310000$xmkdkyjsCmFEi2U.exnetg$UYnG78UZhBY/6Fb8ztGsKdJDtJdIRUrki4bngIPnsOfKxddzQovCDZ8AWETFim0Nar5AhbecJJTEM1kf2lG3WQ";
public = false;
authorization_policy = "two_factor";
require_pkce = true;
pkce_challenge_method = "S256";
redirect_uris =
[ "https://git.stuce.ch/user/oauth2/authelia/callback" ];
scopes = [ "openid" "email" "profile" ];
response_types = [ "code" ];
grant_types = [ "authorization_code" ];
access_token_signed_response_alg = "none";
userinfo_signed_response_alg = "none";
token_endpoint_auth_method = "client_secret_basic";
}];
};
};
access_control = {
default_policy = "deny";
rules = [
{
domain = "todo.Stuce.ch";
policy = "one_factor";
# resources = ["^/.*"];
subject = [ "group:maison" ];
}
{
domain = "armee.stuce.ch";
policy = "one_factor";
resources = [ "^/todo.*" ];
subject = [ "user:sgt" ];
}
{
domain = "vault.stuce.ch";
policy = "two_factor";
resources = [ "^/admin.*" ];
subject = [ "user:stuce" ];
}
{
domain = "ldap.stuce.ch";
policy = "two_factor";
subject = [ "user:stuce" ];
}
{
domain = "armee.stuce.ch";
policy = "one_factor";
resources = [ "^/notes.*" ];
subject = [ "group:ada" "group:cader" ];
}
{
domain = "armee.stuce.ch";
policy = "one_factor";
resources = [ "^/plans.*" ];
subject = [ "user:lt" ];
}
];
};
};
};
}

89
configuration.nix Normal file
View file

@ -0,0 +1,89 @@
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page, on
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).
{ config, lib, pkgs, ... }:
{
imports = [ # Include the results of the hardware scan.
./hardware-configuration.nix
./nginx.nix
./forgejo.nix
./authelia.nix
./lldap.nix
./vaultwarden.nix
./radicale.nix
];
# Add flake support
nix.settings.experimental-features = [ "nix-command" "flakes" ];
# Use the GRUB 2 boot loader.
networking.usePredictableInterfaceNames = true;
users.users.stuce = {
isNormalUser = true;
home = "/home/stuce";
description = "Stuce";
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBcOyttPiox/YITnjSXzUXkuaeOySy6D+wzBiqSwE9AL lefabricesaucy@outlook.com"
];
};
boot.loader.grub.enable = true;
# boot.loader.grub.efiSupport = true;
# boot.loader.grub.efiInstallAsRemovable = true;
# boot.loader.efi.efiSysMountPoint = "/boot/efi";
# Define on which hard drive you want to install Grub.
boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only
networking.hostName = "nixos"; # Define your hostname.
# Set your time zone.
time.timeZone = "Europe/Amsterdam";
# List packages installed in system profile. To search, run:
# $ nix search wget
environment.systemPackages = with pkgs; [
# Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
wget
sqlite
git
htop
];
programs.neovim.enable = true;
programs.neovim.defaultEditor = true;
# Some programs need SUID wrappers, can be configured further or are
# started in user sessions.
# programs.mtr.enable = true;
# programs.gnupg.agent = {
# enable = true;
# enableSSHSupport = true;
# };
# List services that you want to enable:
services.fail2ban.enable = true;
services.openssh = {
enable = true;
startWhenNeeded = true;
settings = {
PasswordAuthentication = false;
UsePAM = false;
PrintMotd = true;
PermitRootLogin = "no";
KbdInteractiveAuthentication = false;
};
};
# Open ports in the firewall.
networking.firewall.allowedTCPPorts = [ 80 443 ];
# networking.firewall.allowedUDPPorts = [ ];
system.stateVersion = "25.05";
environment.etc."motd" = {
text = ''
Successfully connected so stuce's vps !
'';
};
}

40
flake.nix Normal file
View file

@ -0,0 +1,40 @@
{
description = "Config flake";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
# nvf = {
# url = "github:notashelf/nvf";
# inputs.nixpkgs.follows = "nixpkgs";
# };
# home-manager = {
# url = "github:nix-community/home-manager";
# inputs.nixpkgs.follows = "nixpkgs";
# };
# sTodo = {
# url = "git+https://git.stuce.ch/stuce/sTodo";
# };
};
outputs = { self, nixpkgs,
# home-manager,
# nvf,
sTodo, ... }: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = nixpkgs;
modules = [
./configuration.nix
# nvf.nixosModules.default
sTodo.nixosModules.sTodo
# home-manager.nixosModules.home-manager
# {
# home-manager.useGlobalPkgs = true;
# home-manager.users.stuce.imports = [./home.nix];
# }
];
};
};
}

20
forgejo.nix Normal file
View file

@ -0,0 +1,20 @@
{
services.forgejo = {
enable = true;
settings = {
server = { ROOT_URL = "https://git.stuce.ch"; };
openid = {
ENABLE_OPENID_SIGNIN = false;
ENABLE_OPENID_SIGNUP = true;
WHITELISTED_URIS = "auth.stuce.ch";
};
service = {
DISABLE_REGISTRATION = false;
ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
SHOW_REGISTRATION_BUTTON = false;
};
session = { COOKIE_SECURE = true; };
};
};
}

View file

@ -0,0 +1,35 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
boot.initrd.availableKernelModules =
[ "ata_piix" "virtio_pci" "virtio_scsi" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/25df457a-21d0-41ab-9de5-88ffc00e3469";
fsType = "btrfs";
};
fileSystems."/efi" = {
device = "systemd-1";
fsType = "autofs";
};
swapDevices = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.eth0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

23
lldap.nix Normal file
View file

@ -0,0 +1,23 @@
{
services.lldap = {
enable = true;
settings = {
ldap_base_dn = "dc=stuce,dc=ch";
# forces localhost only !
ldap_host = "127.0.0.1";
http_host = "127.0.0.1";
ldap_user_email = "admin@example.com";
ldap_user_dn = "stuce_admin";
ldap_key = ""; # so warning shuts up !
# NOTE: this is in case of oopsies !
force_ldap_user_pass_reset = false;
# TODO: jwt file + user password + key seed script to gen
};
environment = {
LLDAP_JWT_SECRET_FILE = "/var/lib/lldap/jwt_secret";
LLDAP_LDAP_USER_PASS_FILE = "/var/lib/lldap/user_password";
LLDAP_KEY_SEED = "/var/lib/lldap/key_seed";
};
};
}

265
nginx.nix Normal file
View file

@ -0,0 +1,265 @@
{ config, pkgs, ... }:
let host = "stuce.ch";
in {
security.acme = {
acceptTerms = true;
defaults.email = "lefabricesaucy@outlook.com";
};
services.nginx = {
enable = true;
# Use recommended settings
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
# Only allow PFS-enabled ciphers with AES256
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
virtualHosts."cal.${host}" = {
enableACME = true;
forceSSL = true;
extraConfig =
" rewrite ^/.well-known/carddav / redirect;\n rewrite ^/.well-known/caldav / redirect;\n ";
locations."/" = {
proxyPass = "http://localhost:5232";
# extraConfig = ''
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Host $host;
# proxy_set_header X-Forwarded-Port $server_port;
# proxy_set_header X-Forwarded-Proto $scheme;
# proxy_set_header Host $http_host;
# proxy_pass_header Authorization;
# '';
};
};
virtualHosts."eink.${host}" = {
forceSSL = true;
sslCertificateKey = "/etc/nginx/certs/ca.key";
sslCertificate = "/etc/nginx/certs/ca.crt";
extraConfig = "ssl_client_certificate /etc/nginx/certs/client.crt;";
locations."/" = {
# TODO fastcgi to the script
extraConfig = "return 200 'handshake worked !!!';";
};
};
virtualHosts."vault.${host}" = {
enableACME = true;
forceSSL = true;
extraConfig = "include /etc/nginx/snippets/authelia-location.conf;";
locations."/" = {
proxyPass = "http://127.0.0.1:${
toString config.services.vaultwarden.config.ROCKET_PORT
}";
};
locations."/admin" = {
extraConfig = ''
include /etc/nginx/snippets/proxy.conf;
include /etc/nginx/snippets/authelia-authrequest.conf;
'';
proxyPass = "http://127.0.0.1:${
toString config.services.vaultwarden.config.ROCKET_PORT
}";
};
};
virtualHosts."armee.${host}" = {
root = "/var/www/armee";
forceSSL = true;
enableACME = true;
extraConfig = "include /etc/nginx/snippets/authelia-location.conf;";
locations."/plans" = {
extraConfig = ''
autoindex on;
include /etc/nginx/snippets/proxy.conf;
include /etc/nginx/snippets/authelia-authrequest.conf;
'';
};
locations."/notes" = {
extraConfig = ''
include /etc/nginx/snippets/proxy.conf;
include /etc/nginx/snippets/authelia-authrequest.conf;
'';
};
};
virtualHosts."auth.${host}" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://localhost:9091";
proxyWebsockets = true;
extraConfig = "include /etc/nginx/snippets/proxy.conf;";
};
locations."/api/verify" = { proxyPass = "http://localhost:9091"; };
locations."/api/authz" = { proxyPass = "http://localhost:9091"; };
};
virtualHosts."ldap.${host}" = {
forceSSL = true;
enableACME = true;
extraConfig = "include /etc/nginx/snippets/authelia-location.conf;";
locations."/" = {
proxyPass = "http://localhost:17170";
extraConfig = "include /etc/nginx/snippets/proxy.conf;";
};
};
virtualHosts."git.${host}" = {
forceSSL = true;
enableACME = true;
locations."/" = {
extraConfig = ''
client_max_body_size 512M;
proxy_pass http://localhost:3000;
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
'';
};
};
};
# TODO: make a simple script around here that lets you regenerate or update every value when needed
# NOTE: does not work as expected
# systemd.services.authelia-main.preStart = ''
# [ -f /var/lib/authelia-main/jwt-secret ] || {
# "${pkgs.openssl}/bin/openssl" rand -base64 32 > /var/lib/authelia-main/jwtSecret
# }
# [ -f /var/lib/authelia-main/storage-encryption-file ] || {
# "${pkgs.openssl}/bin/openssl" rand -base64 32 > /var/lib/authelia-main/storageEncryptionKeyFile
# }
# [ -f /var/lib/authelia-main/session-secret-file ] || {
# "${pkgs.openssl}/bin/openssl" rand -base64 32 > /var/lib/authelia-main/sessionSecretFile
# }
# [ -f /var/lib/authelia-main/hmac ] || {
# "${pkgs.openssl}/bin/openssl" rand -base64 64 > /var/lib/authelia-main/hmac
# }
# [ -f /var/lib/authelia-main/rsa.2048.key ] || {
# "${pkgs.openssl}/bin/openssl" genpkey -algorithm RSA -out /var/lib/authelia-main/rsa.2048.key -pkeyopt rsa_keygen_bits:2048
# }
# '';
environment.etc."nginx/snippets/authelia-location.conf" = {
user = "nginx";
group = "nginx";
text = ''
set $upstream_authelia http://localhost:9091/api/authz/auth-request;
## Virtual endpoint created by nginx to forward auth requests.
location /internal/authelia/authz {
## Essential Proxy Configuration
internal;
proxy_pass $upstream_authelia;
## Headers
## The headers starting with X-* are required.
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Content-Length "";
proxy_set_header Connection "";
## Basic Proxy Configuration
proxy_pass_request_body off;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; # Timeout if the real server is dead
proxy_redirect http:// $scheme://;
#proxy_http_version 1.1;
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 4 32k;
client_body_buffer_size 128k;
## Advanced Proxy Configuration
send_timeout 5m;
proxy_read_timeout 240;
proxy_send_timeout 240;
proxy_connect_timeout 240;
}
'';
};
environment.etc."nginx/snippets/authelia-authrequest.conf" = {
user = "nginx";
group = "nginx";
text = ''
## Send a subrequest to Authelia to verify if the user is authenticated and has permission to access the resource.
auth_request /internal/authelia/authz;
## Save the upstream metadata response headers from Authelia to variables.
auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups;
auth_request_set $name $upstream_http_remote_name;
auth_request_set $email $upstream_http_remote_email;
## Inject the metadata response headers from the variables into the request made to the backend.
proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups;
proxy_set_header Remote-Email $email;
proxy_set_header Remote-Name $name;
## Configure the redirection when the authz failure occurs. Lines starting with 'Modern Method' and 'Legacy Method'
## should be commented / uncommented as pairs. The modern method uses the session cookies configuration's authelia_url
## value to determine the redirection URL here. It's much simpler and compatible with the mutli-cookie domain easily.
## Modern Method: Set the $redirection_url to the Location header of the response to the Authz endpoint.
auth_request_set $redirection_url $upstream_http_location;
## Modern Method: When there is a 401 response code from the authz endpoint redirect to the $redirection_url.
error_page 401 =302 $redirection_url;
## Legacy Method: Set $target_url to the original requested URL.
## This requires http_set_misc module, replace 'set_escape_uri' with 'set' if you don't have this module.
# set_escape_uri $target_url $scheme://$http_host$request_uri;
## Legacy Method: When there is a 401 response code from the authz endpoint redirect to the portal with the 'rd'
## URL parameter set to $target_url. This requires users update 'auth.stuce.com/' with their external authelia URL.
# error_page 401 =302 https://auth.stuce.com/?rd=$target_url;
'';
};
environment.etc."nginx/snippets/proxy.conf" = {
user = "nginx";
group = "nginx";
text = ''
## Headers
proxy_set_header Host $host;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-URI $request_uri;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
## Basic Proxy Configuration
client_body_buffer_size 128k;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; ## Timeout if the real server is dead.
proxy_redirect http:// $scheme://;
#proxy_http_version 1.1;
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 64 256k;
## Trusted Proxies Configuration
## Please read the following documentation before configuring this:
## https://www.authelia.com/integration/proxies/nginx/#trusted-proxies
# set_real_ip_from 10.0.0.0/8;
# set_real_ip_from 172.16.0.0/12;
# set_real_ip_from 192.168.0.0/16;
# set_real_ip_from fc00::/7;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
## Advanced Proxy Configuration
send_timeout 5m;
proxy_read_timeout 360;
proxy_send_timeout 360;
proxy_connect_timeout 360;
'';
};
}

19
radicale.nix Normal file
View file

@ -0,0 +1,19 @@
{...}:{
services.radicale = {
enable = true;
settings = {
server.hosts = [ "0.0.0.0:5232" ];
auth = {
type = "ldap";
ldap_uri = "ldap://localhost:3890";
ldap_base = "dc=stuce,dc=ch";
ldap_reader_dn = "uid=bind_user_radicale,ou=people,dc=stuce,dc=ch";
ldap_secret_file = "/var/lib/radicale/ldap_password";
ldap_filter = "(&(objectClass=person)(uid={0})(memberOf=cn=calendrier,ou=groups,dc=stuce,dc=ch))";
# ldap_filter = "(&(objectClass=person)(uid={0}))";
lc_username = true;
};
};
};
}

0
sTodo.nix Normal file
View file

23
vaultwarden.nix Normal file
View file

@ -0,0 +1,23 @@
{
services.vaultwarden = {
enable = true;
config = {
DOMAIN = "https://vault.stuce.ch";
SIGNUPS_ALLOWED = false;
INVITATIONS_ALLOWED = false;
SMTP_HOST = "mail.infomaniak.com";
SMTP_PORT = "465";
SMTP_FROM = "no-reply@stuce.ch";
SMTP_FROM_NAME = "Stuce's vaultwarden";
SMTP_USERNAME = "no-reply@stuce.ch";
SMTP_PASSWORD_FILE = "/var/lib/vaultwarden/smtp_password";
SMTP_SECURITY = "force_tls";
ADMIN_TOKEN =
"$argon2id$v=19$m=65540,t=3,p=4$Ic844Ym+XKWlEcj5mVjk9WsWO13bF+iWTbqWlTRESzo$DPncN5oYnFXfea57zBdVC80dEzNQkkKMqdzGRIAAb/o";
ROCKET_PORT = 8222;
};
backupDir = "/var/backup/vaultwarden";
};
}