tofu workflow
Some checks failed
Test / tests (push) Has been cancelled
/ OpenTofu (push) Failing after 13s

This commit is contained in:
plasmagoat 2025-07-21 22:33:04 +02:00
parent 6972897c46
commit acc0dac234
26 changed files with 674 additions and 156 deletions

View file

@ -0,0 +1,44 @@
on:
push:
workflow_dispatch:
jobs:
apply:
name: OpenTofu
# Ensure 'nixos-latest' runner has Docker, SSH client, and basic Nix tools installed.
# It seems it already does.
runs-on: nixos-latest
env:
PROXMOX_API_URL: https://192.168.1.205:8006/api2/json
# PROXMOX_API_TOKEN_ID: nixos-builder.lab
# PROXMOX_API_TOKEN_SECRET: nixos-builder.lab
steps:
- name: Install dependencies
run: |
nix-env -iA nixpkgs.nodejs
nix-env -iA nixpkgs.openssh
nix-env -iA nixpkgs.opentofu
- uses: actions/checkout@v3
- name: OpenTofu fmt
id: fmt
run: tofu fmt -check
continue-on-error: true
- name: OpenTofu Init
id: init
run: tofu init
working-directory: /infrastructure/proxmox
- name: OpenTofu Validate
id: validate
run: tofu validate -no-color
working-directory: /infrastructure/proxmox
- name: OpenTofu Plan
id: plan
run: tofu plan -no-color
working-directory: /infrastructure/proxmox
continue-on-error: true

17
flake.lock generated
View file

@ -186,6 +186,22 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-unstable": {
"locked": {
"lastModified": 1752480373,
"narHash": "sha256-JHQbm+OcGp32wAsXTE/FLYGNpb+4GLi5oTvCxwSoBOA=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "62e0f05ede1da0d54515d4ea8ce9c733f12d9f08",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1752624097, "lastModified": 1752624097,
@ -205,6 +221,7 @@
"inputs": { "inputs": {
"colmena": "colmena", "colmena": "colmena",
"nixpkgs": "nixpkgs_2", "nixpkgs": "nixpkgs_2",
"nixpkgs-unstable": "nixpkgs-unstable",
"simple-nixos-mailserver": "simple-nixos-mailserver", "simple-nixos-mailserver": "simple-nixos-mailserver",
"sops-nix": "sops-nix" "sops-nix": "sops-nix"
} }

View file

@ -2,17 +2,18 @@
description = "Declarative NixOS HomeLab"; description = "Declarative NixOS HomeLab";
inputs = { inputs = {
# Nixpkgs
nixpkgs.url = "github:nixos/nixpkgs"; nixpkgs.url = "github:nixos/nixpkgs";
# You can access packages and modules from different nixpkgs revs
# at the same time. Here's an working example:
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
# Also see the 'unstable-packages' overlay at 'overlays/default.nix'.
# systems.url = "github:nix-systems/default"; # systems.url = "github:nix-systems/default";
sops-nix = { sops-nix.url = "github:Mic92/sops-nix";
url = "github:Mic92/sops-nix"; sops-nix.inputs.nixpkgs.follows = "nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
simple-nixos-mailserver = { simple-nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver";
url = "gitlab:simple-nixos-mailserver/nixos-mailserver"; simple-nixos-mailserver.inputs.nixpkgs.follows = "nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
# home-manager = { # home-manager = {
# url = "home-manager"; # url = "home-manager";
# inputs.nixpkgs.follows = "nixpkgs"; # inputs.nixpkgs.follows = "nixpkgs";
@ -30,11 +31,56 @@
simple-nixos-mailserver, simple-nixos-mailserver,
... ...
} @ inputs: let } @ inputs: let
inherit (self) outputs;
# Supported systems for your flake packages, shell, etc.
systems = [
"x86_64-linux"
];
# This is a function that generates an attribute by calling a function you
# pass to it, with each system as an argument
forAllSystems = nixpkgs.lib.genAttrs systems;
in {
# Custom packages
# Accessible through 'nix build', 'nix shell', etc
packages = forAllSystems (system: import ./pkgs nixpkgs.legacyPackages.${system});
# Formatter for your nix files, available through 'nix fmt'
# Other options beside 'alejandra' include 'nixpkgs-fmt'
formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.alejandra);
# Custom packages and modifications, exported as overlays
overlays = import ./overlays {inherit inputs;};
# Reusable nixos modules
nixosModules = import ./modules/nixos;
colmenaHive = colmena.lib.makeHive self.outputs.colmena;
colmena = {
meta = {
nixpkgs = import nixpkgs {
system = "x86_64-linux";
overlays = [ overlays = [
outputs.overlays.additions
outputs.overlays.modifications
outputs.overlays.unstable-packages
colmena.overlays.default colmena.overlays.default
]; ];
in { config.allowUnfree = true;
colmenaHive = colmena.lib.makeHive self.outputs.colmena; };
colmena = (import ./hive.nix) (inputs // {inherit overlays;});
specialArgs = {
inherit inputs outputs;
};
};
defaults = import ./machines/_default/configuration.nix;
sandbox = import ./machines/sandbox/configuration.nix;
auth = import ./machines/auth/configuration.nix;
mail = import ./machines/mail/configuration.nix;
monitor = import ./machines/monitor/configuration.nix;
photos = import ./machines/photos/configuration.nix;
};
}; };
} }

View file

@ -4,36 +4,9 @@ inputs @ {
sops-nix, sops-nix,
simple-nixos-mailserver, simple-nixos-mailserver,
# home-manager, # home-manager,
overlays, outputs,
... ...
}: { }: {
meta = {
nixpkgs = import nixpkgs {
system = "x86_64-linux";
};
specialArgs.flakeInputs = inputs;
};
defaults = {
lib,
name,
config,
...
}: {
imports = [
./machines/_default
./machines/modules
sops-nix.nixosModules.sops
# home-manager.nixosModules.home-manager
];
nixpkgs = {
inherit overlays;
system = lib.mkDefault "x86_64-linux";
config.allowUnfree = true;
};
deployment.tags = [config.nixpkgs.system name];
};
sandbox = {name, ...}: { sandbox = {name, ...}: {
imports = [./machines/${name}/definition.nix]; imports = [./machines/${name}/definition.nix];
deployment.tags = ["sandbox"]; deployment.tags = ["sandbox"];
@ -56,4 +29,9 @@ inputs @ {
]; ];
deployment.tags = ["mail"]; deployment.tags = ["mail"];
}; };
photos = {name, ...}: {
imports = [./machines/${name}/definition.nix];
deployment.tags = ["ente"];
};
} }

View file

@ -1,10 +1,15 @@
{ {
lib,
name, name,
config,
lib,
inputs,
... ...
}: { }: {
imports = [ imports = [
./common_config.nix ./common_config.nix
../modules
inputs.sops-nix.nixosModules.sops
# inputs.home-manager.nixosModules.home-manager
]; ];
networking.hostName = name; networking.hostName = name;
@ -13,7 +18,7 @@
replaceUnknownProfiles = lib.mkDefault true; replaceUnknownProfiles = lib.mkDefault true;
buildOnTarget = lib.mkDefault false; buildOnTarget = lib.mkDefault false;
targetHost = lib.mkDefault "${name}.lab"; targetHost = lib.mkDefault "${name}.lab";
tags = lib.mkDefault ["homelab"]; tags = lib.mkDefault [config.nixpkgs.system name "homelab"];
}; };
sops = { sops = {
@ -21,20 +26,6 @@
defaultSopsFile = ../../secrets/secrets.yaml; defaultSopsFile = ../../secrets/secrets.yaml;
}; };
# home-manager = {
# useGlobalPkgs = true;
# useUserPackages = true;
# users.cottand = {
# imports = with flakeInputs.cottand.homeManagerModules; [cli];
# home.stateVersion = "22.11";
# };
# users.root = {
# imports = with flakeInputs.cottand.homeManagerModules; [cli];
# home.stateVersion = "22.11";
# };
# };
# consulNode.enable = lib.mkDefault true;
nodeExporter.enable = lib.mkDefault true; nodeExporter.enable = lib.mkDefault true;
journalLog.enable = lib.mkDefault true; journalLog.enable = lib.mkDefault true;
} }

View file

@ -17,7 +17,7 @@
} }
{ {
"id": "forgejo", "id": "forgejo",
"email": "forgejo@procopius.dk", "email": "git@procopius.dk",
"password": "${config.sops.placeholder."service_accounts/forgejo/password"}", "password": "${config.sops.placeholder."service_accounts/forgejo/password"}",
"displayName": "Forgejo", "displayName": "Forgejo",
"groups": [ "groups": [

View file

@ -6,5 +6,6 @@
./redis.nix ./redis.nix
]; ];
deployment.tags = ["authelia" "sso" "ldap" "lldap"];
system.stateVersion = "25.05"; system.stateVersion = "25.05";
} }

View file

@ -0,0 +1,11 @@
{inputs, ...}: {
imports = [
./mailserver.nix
./networking.nix
inputs.simple-nixos-mailserver.nixosModule
];
deployment.tags = ["mail"];
system.stateVersion = "25.05";
}

View file

@ -1,8 +1,4 @@
{ {
imports = [
./mailserver.nix
];
networking = { networking = {
interfaces.eth0.ipv4.addresses = [ interfaces.eth0.ipv4.addresses = [
{ {
@ -13,7 +9,4 @@
nameservers = ["192.168.1.53"]; nameservers = ["192.168.1.53"];
defaultGateway = "192.168.1.1"; defaultGateway = "192.168.1.1";
}; };
deployment.targetHost = "192.168.1.25";
system.stateVersion = "25.05";
} }

View file

@ -10,5 +10,7 @@
./jellyfin-exporter.nix ./jellyfin-exporter.nix
]; ];
deployment.tags = ["grafana" "prometheus"];
system.stateVersion = "25.05"; system.stateVersion = "25.05";
} }

View file

@ -0,0 +1,10 @@
{outputs, ...}: {
imports = [
outputs.nixosModules.ente
./ente.nix
];
deployment.tags = ["ente"];
system.stateVersion = "25.05";
}

25
machines/photos/ente.nix Normal file
View file

@ -0,0 +1,25 @@
{
services.ente.api = {
enable = true;
enableLocalDB = true;
domain = "ente-v2.procopius.dk";
settings = {
# apps = {
# accounts = "https://accounts.procopius.dk";
# cast = "https://cast.procopius.dk";
# public-albums = "https://albums.procopius.dk";
# };
};
};
services.ente.web = {
enable = true;
domains = {
api = "ente-v2.procopius.dk";
accounts = "accounts.procopius.dk";
albums = "albums.procopius.dk";
cast = "cast.procopius.dk";
photos = "photos.procopius.dk";
};
};
}

View file

@ -0,0 +1,6 @@
{
services.minio = {
enable = true;
rootCredentialsFile = "/etc/nixos/minio-root-credentials";
};
}

View file

@ -1,3 +1,5 @@
{ {
deployment.tags = ["sandbox"];
system.stateVersion = "25.05"; system.stateVersion = "25.05";
} }

View file

@ -0,0 +1,3 @@
{
ente = import ./ente.nix;
}

351
modules/nixos/ente.nix Normal file
View file

@ -0,0 +1,351 @@
{
config,
lib,
pkgs,
utils,
...
}: let
inherit
(lib)
getExe
mkDefault
mkEnableOption
mkIf
mkMerge
mkOption
mkPackageOption
optional
types
;
cfgApi = config.services.ente.api;
cfgWeb = config.services.ente.web;
webPackage = enteApp:
cfgWeb.package.override {
inherit enteApp;
enteMainUrl = "https://${cfgWeb.domains.photos}";
extraBuildEnv = {
NEXT_PUBLIC_ENTE_ENDPOINT = "https://${cfgWeb.domains.api}";
NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT = "https://${cfgWeb.domains.albums}";
NEXT_TELEMETRY_DISABLED = "1";
};
};
defaultUser = "ente";
defaultGroup = "ente";
dataDir = "/var/lib/ente";
yamlFormat = pkgs.formats.yaml {};
in {
options.services.ente = {
web = {
enable = mkEnableOption "Ente web frontend (Photos, Albums)";
package = mkPackageOption pkgs "ente-web" {};
domains = {
api = mkOption {
type = types.str;
description = ''
The domain under which the api is served. This will NOT serve the api itself,
but is a required setting to host the frontends! This will automatically be set
for you if you enable both the api server and web frontends.
'';
};
accounts = mkOption {
type = types.str;
description = "The domain under which the accounts frontend will be served.";
};
cast = mkOption {
type = types.str;
description = "The domain under which the cast frontend will be served.";
};
albums = mkOption {
type = types.str;
description = "The domain under which the albums frontend will be served.";
};
photos = mkOption {
type = types.str;
description = "The domain under which the photos frontend will be served.";
};
};
};
api = {
enable = mkEnableOption "Museum (API server for ente.io)";
package = mkPackageOption pkgs "museum" {};
nginx.enable = mkEnableOption "nginx proxy for the API server";
user = mkOption {
type = types.str;
default = defaultUser;
description = "User under which museum runs.";
};
group = mkOption {
type = types.str;
default = defaultGroup;
description = "Group under which museum runs.";
};
domain = mkOption {
type = types.str;
description = "The domain under which the api will be served.";
};
enableLocalDB = mkEnableOption "the automatic creation of a local postgres database for museum.";
settings = mkOption {
description = ''
Museum yaml configuration. Refer to upstream [local.yaml](https://github.com/ente-io/ente/blob/main/server/configurations/local.yaml) for more information.
You can specify secret values in this configuration by setting `somevalue._secret = "/path/to/file"` instead of setting `somevalue` directly.
'';
default = {};
type = types.submodule {
freeformType = yamlFormat.type;
options = {
apps = {
public-albums = mkOption {
type = types.str;
default = "https://albums.ente.io";
description = ''
If you're running a self hosted instance and wish to serve public links,
set this to the URL where your albums web app is running.
'';
};
cast = mkOption {
type = types.str;
default = "https://cast.ente.io";
description = ''
Set this to the URL where your cast page is running.
This is for browser and chromecast casting support.
'';
};
accounts = mkOption {
type = types.str;
default = "https://accounts.ente.io";
description = ''
Set this to the URL where your accounts page is running.
This is primarily for passkey support.
'';
};
};
db = {
host = mkOption {
type = types.str;
description = "The database host";
};
port = mkOption {
type = types.port;
default = 5432;
description = "The database port";
};
name = mkOption {
type = types.str;
description = "The database name";
};
user = mkOption {
type = types.str;
description = "The database user";
};
};
};
};
};
};
};
config = mkMerge [
(mkIf cfgApi.enable {
services.postgresql = mkIf cfgApi.enableLocalDB {
enable = true;
ensureUsers = [
{
name = "ente";
ensureDBOwnership = true;
}
];
ensureDatabases = ["ente"];
};
services.ente.web.domains.api = mkIf cfgWeb.enable cfgApi.domain;
services.ente.api.settings = {
log-file = mkDefault "";
db = mkIf cfgApi.enableLocalDB {
host = "/run/postgresql";
port = 5432;
name = "ente";
user = "ente";
};
};
systemd.services.ente = {
description = "Ente.io Museum API Server";
after = ["network.target"] ++ optional cfgApi.enableLocalDB "postgresql.service";
requires = optional cfgApi.enableLocalDB "postgresql.service";
wantedBy = ["multi-user.target"];
preStart = ''
# Generate config including secret values. YAML is a superset of JSON, so we can use this here.
${utils.genJqSecretsReplacementSnippet cfgApi.settings "/run/ente/local.yaml"}
# Setup paths
mkdir -p ${dataDir}/configurations
ln -sTf /run/ente/local.yaml ${dataDir}/configurations/local.yaml
'';
serviceConfig = {
ExecStart = getExe cfgApi.package;
Type = "simple";
Restart = "on-failure";
AmbientCapablities = [];
CapabilityBoundingSet = [];
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = false;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = "@system-service";
UMask = "077";
BindReadOnlyPaths = [
"${cfgApi.package}/share/museum/migrations:${dataDir}/migrations"
"${cfgApi.package}/share/museum/mail-templates:${dataDir}/mail-templates"
];
User = cfgApi.user;
Group = cfgApi.group;
SyslogIdentifier = "ente";
StateDirectory = "ente";
WorkingDirectory = dataDir;
RuntimeDirectory = "ente";
};
# Environment MUST be called local, otherwise we cannot log to stdout
environment = {
ENVIRONMENT = "local";
GIN_MODE = "release";
};
};
users = {
users = mkIf (cfgApi.user == defaultUser) {
${defaultUser} = {
description = "ente.io museum service user";
inherit (cfgApi) group;
isSystemUser = true;
home = dataDir;
};
};
groups = mkIf (cfgApi.group == defaultGroup) {${defaultGroup} = {};};
};
services.nginx = mkIf cfgApi.nginx.enable {
enable = true;
upstreams.museum = {
servers."localhost:8080" = {};
extraConfig = ''
zone museum 64k;
keepalive 20;
'';
};
virtualHosts.${cfgApi.domain} = {
forceSSL = mkDefault false;
locations."/".proxyPass = "http://museum";
extraConfig = ''
client_max_body_size 4M;
'';
};
};
})
(mkIf cfgWeb.enable {
services.ente.api.settings = mkIf cfgApi.enable {
apps = {
accounts = "https://${cfgWeb.domains.accounts}";
cast = "https://${cfgWeb.domains.cast}";
public-albums = "https://${cfgWeb.domains.albums}";
};
webauthn = {
rpid = cfgWeb.domains.accounts;
rporigins = ["https://${cfgWeb.domains.accounts}"];
};
};
services.nginx = let
domainFor = app: cfgWeb.domains.${app};
in {
enable = true;
virtualHosts.${domainFor "accounts"} = {
forceSSL = mkDefault false;
locations."/" = {
root = webPackage "accounts";
tryFiles = "$uri $uri.html /index.html";
extraConfig = ''
add_header Access-Control-Allow-Origin 'https://${cfgWeb.domains.api}';
'';
};
};
virtualHosts.${domainFor "cast"} = {
forceSSL = mkDefault false;
locations."/" = {
root = webPackage "cast";
tryFiles = "$uri $uri.html /index.html";
extraConfig = ''
add_header Access-Control-Allow-Origin 'https://${cfgWeb.domains.api}';
'';
};
};
virtualHosts.${domainFor "photos"} = {
serverAliases = [
(domainFor "albums") # the albums app is shared with the photos frontend
];
forceSSL = mkDefault false;
locations."/" = {
root = webPackage "photos";
tryFiles = "$uri $uri.html /index.html";
extraConfig = ''
add_header Access-Control-Allow-Origin 'https://${cfgWeb.domains.api}';
'';
};
};
};
})
];
meta.maintainers = with lib.maintainers; [oddlama];
}

View file

@ -16,6 +16,11 @@ in {
user = "forgejo"; user = "forgejo";
group = "forgejo"; group = "forgejo";
stateDir = "/srv/forgejo"; stateDir = "/srv/forgejo";
secrets = {
mailer = {
PASSWD = ;
};
};
settings = { settings = {
# https://forgejo.org/docs/latest/admin/config-cheat-sheet/ # https://forgejo.org/docs/latest/admin/config-cheat-sheet/
server = { server = {
@ -34,8 +39,7 @@ in {
PROTOCOL = "smtp+starttls"; PROTOCOL = "smtp+starttls";
SMTP_ADDR = "mail.procopius.dk"; SMTP_ADDR = "mail.procopius.dk";
USER = "admin@procopius.dk"; USER = "git@procopius.dk";
PASSWD = "mikael";
}; };
database = { database = {
DB_TYPE = lib.mkForce "postgres"; DB_TYPE = lib.mkForce "postgres";
@ -57,9 +61,9 @@ in {
ZOMBIE_TASK_TIMEOUT = "30m"; ZOMBIE_TASK_TIMEOUT = "30m";
}; };
ldap = { ldap = {
AUTHORIZATION_NAME = "My LDAP"; AUTHORIZATION_NAME = "LLDAP";
HOST = "ldap.example.com"; HOST = "auth.lab";
PORT = 389; PORT = 3890;
ENABLE_TLS = false; ENABLE_TLS = false;
USER_SEARCH_BASE = "ou=users,dc=example,dc=com"; USER_SEARCH_BASE = "ou=users,dc=example,dc=com";
USER_FILTER = "(&(objectClass=user)(sAMAccountName=%[1]s))"; USER_FILTER = "(&(objectClass=user)(sAMAccountName=%[1]s))";
@ -86,7 +90,6 @@ in {
security = { security = {
INSTALL_LOCK = true; INSTALL_LOCK = true;
SECRET_KEY = config.sops.secrets."forgejo-secret-key".path; # can be another secret
}; };
}; };
}; };

View file

@ -1,18 +1,4 @@
{ {
# services.nfs.client = {
# enable = true;
# idmapd.enable = true;
# };
# environment.etc."idmapd.conf".text = ''
# [General]
# Domain = localdomain
# [Mapping]
# Nobody-User = nobody
# Nobody-Group = nogroup
# '';
boot.supportedFilesystems = ["nfs"]; boot.supportedFilesystems = ["nfs"];
services.rpcbind.enable = true; services.rpcbind.enable = true;

View file

@ -1,15 +0,0 @@
{
config,
pkgs,
modulesPath,
lib,
...
}: {
imports = [
../../templates/base.nix
./networking.nix
./storage.nix
./sandbox.nix
./warpgate.nix
];
}

View file

@ -1,6 +0,0 @@
{ config, lib, pkgs, ... }:
{
networking.hostName = "sandbox";
networking.interfaces.ens18.useDHCP = true;
networking.defaultGateway = "192.168.1.1";
}

View file

@ -1,4 +0,0 @@
{ config, pkgs, modulesPath, lib, ... }:
{
}

View file

@ -1,11 +0,0 @@
{
boot.supportedFilesystems = ["nfs"];
services.rpcbind.enable = true;
# fileSystems."/mnt/nas" = {
# device = "192.168.1.226:/volume1/docker";
# fsType = "nfs";
# options = [ "noatime" "vers=4" "rsize=8192" "wsize=8192" ];
# };
}

View file

@ -1,35 +0,0 @@
{
virtualisation = {
containers.enable = true;
oci-containers.backend = "podman";
podman = {
enable = true;
# Create a `docker` alias for podman, to use it as a drop-in replacement
dockerCompat = true;
# Required for containers under podman-compose to be able to talk to each other.
defaultNetwork.settings.dns_enabled = true;
};
};
virtualisation.oci-containers.containers = {
warpgate = {
image = "ghcr.io/warp-tech/warpgate";
ports = [
"2222:2222"
"8888:8888"
];
volumes = [
"/srv/warpgate/data:/data"
];
};
};
systemd.tmpfiles.rules = [
"d /srv/warpgate 0755 root root -"
"d /srv/warpgate/data 0755 root root -"
];
networking.firewall.allowedTCPPorts = [8888];
}

23
overlays/default.nix Normal file
View file

@ -0,0 +1,23 @@
# This file defines overlays
{inputs, ...}: {
# This one brings our custom packages from the 'pkgs' directory
additions = final: _prev: import ../pkgs final.pkgs;
# This one contains whatever you want to overlay
# You can change versions, add patches, set compilation flags, anything really.
# https://nixos.wiki/wiki/Overlays
modifications = final: prev: {
# example = prev.example.overrideAttrs (oldAttrs: rec {
# ...
# });
};
# When applied, the unstable nixpkgs set (declared in the flake inputs) will
# be accessible through 'pkgs.unstable'
unstable-packages = final: _prev: {
unstable = import inputs.nixpkgs-unstable {
system = final.system;
config.allowUnfree = true;
};
};
}

6
pkgs/default.nix Normal file
View file

@ -0,0 +1,6 @@
# Custom packages, that can be defined similarly to ones from nixpkgs
# You can build them using 'nix build .#example'
pkgs: {
# example = pkgs.callPackage ./example { };
ente-web = pkgs.callPackage ./ente-web.nix {};
}

91
pkgs/ente-web.nix Normal file
View file

@ -0,0 +1,91 @@
{
lib,
stdenv,
fetchFromGitHub,
fetchYarnDeps,
nodejs,
yarnConfigHook,
yarnBuildHook,
nix-update-script,
extraBuildEnv ? {},
# This package contains serveral sub-applications. This specifies which of them you want to build.
enteApp ? "photos",
# Accessing some apps (such as account) directly will result in a hardcoded redirect to ente.io.
# To prevent users from accidentally logging in to ente.io instead of the selfhosted instance, you
# can set this parameter to override these occurrences with your own url. Must include the schema.
# Example: https://my-ente.example.com
enteMainUrl ? null,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "ente-web-${enteApp}";
version = "1.0.4";
src = fetchFromGitHub {
owner = "ente-io";
repo = "ente";
sparseCheckout = ["web"];
tag = "photos-v${finalAttrs.version}";
fetchSubmodules = true;
hash = "sha256-M1kAZgqjbWNn6LqymtWRmAk/v0vWEGbyS50lVrsr85o=";
};
sourceRoot = "${finalAttrs.src.name}/web";
offlineCache = fetchYarnDeps {
yarnLock = "${finalAttrs.src}/web/yarn.lock";
hash = "sha256-EYhYwy6+7bgWckU/7SfL1PREWw9JUgKxWadSVtoZwXs=";
};
nativeBuildInputs = [
yarnConfigHook
yarnBuildHook
nodejs
];
# See: https://github.com/ente-io/ente/blob/main/web/apps/photos/.env
env = extraBuildEnv;
# Replace hardcoded ente.io urls if desired
postPatch = lib.optionalString (enteMainUrl != null) ''
substituteInPlace \
apps/payments/src/services/billing.ts \
apps/photos/src/pages/shared-albums.tsx \
--replace-fail "https://ente.io" ${lib.escapeShellArg enteMainUrl}
substituteInPlace \
apps/accounts/src/pages/index.tsx \
--replace-fail "https://web.ente.io" ${lib.escapeShellArg enteMainUrl}
'';
yarnBuildScript = "build:${enteApp}";
installPhase = let
distName =
if enteApp == "payments"
then "dist"
else "out";
in ''
runHook preInstall
cp -r apps/${enteApp}/${distName} $out
runHook postInstall
'';
passthru.updateScript = nix-update-script {
extraArgs = [
"--version-regex"
"photos-v(.*)"
];
};
meta = {
description = "Ente application web frontends";
homepage = "https://ente.io/";
changelog = "https://github.com/ente-io/ente/releases";
license = lib.licenses.agpl3Only;
maintainers = with lib.maintainers; [
pinpox
oddlama
];
platforms = lib.platforms.all;
};
})