Compare commits

...

15 commits

Author SHA1 Message Date
Florian Schmitt
aa53257d9b feat(config generator): make the select logic between bundles and services work
Some checks failed
deploy to prod / Build and deploy site (push) Failing after 28s
build demo images / Build NixOS images (push) Has been cancelled
2024-09-30 22:18:26 +03:00
f612b5de23 debug build-images action
Some checks failed
build demo images / Build NixOS images (push) Failing after 3m42s
2024-09-30 17:57:06 +02:00
7083a81cd7 debug build-images action
Some checks failed
build demo images / Build NixOS images (push) Failing after 29s
2024-09-30 17:55:18 +02:00
0bd79e32fb try a different way to install nodejs
Some checks failed
build demo images / Build NixOS images (push) Failing after 12s
2024-09-30 17:51:24 +02:00
38e7aaf8ae add an node install step in build-images action
Some checks failed
build demo images / Build NixOS images (push) Failing after 12s
2024-09-30 17:44:42 +02:00
51c1716f19 cleanup debian specific steps in build-images action
Some checks failed
build demo images / Build NixOS images (push) Failing after 13s
2024-09-30 17:23:29 +02:00
647b647eea try to run the build-images action on nixos docker image instead of debian
Some checks failed
build demo images / Build NixOS images (push) Failing after 1m24s
2024-09-30 17:16:39 +02:00
52a9c55a88 add action to build demo images
Some checks failed
build demo images / Build NixOS images (push) Failing after 6m13s
2024-09-30 16:27:50 +02:00
a8b15ebfcb work on technical-principles.md 2024-09-30 16:25:24 +02:00
Florian Schmitt
2c0e68ef9c feat: better vm doc, remove init options 2024-09-30 16:52:30 +03:00
Florian Schmitt
1ee1b8e07b feat(shell): better package name, install npm deps, show options 2024-09-30 15:41:33 +03:00
Florian Schmitt
3fd1bb9044 feat: add shell 2024-09-30 15:06:14 +03:00
Florian Schmitt
311ee6355f new wip demo conf 2024-09-30 12:18:45 +03:00
Florian Schmitt
6b600b6745 wip demo conf 2024-09-30 11:49:45 +03:00
Florian Schmitt
304f412950 feat: build instructions and example 2024-09-28 20:11:22 +03:00
11 changed files with 689 additions and 27 deletions

View file

@ -0,0 +1,16 @@
name: "build demo images"
on:
push:
branches:
- main
jobs:
build:
name: Build NixOS images
runs-on: nixos
steps:
- name: install node
run: nix-env -iA nixpkgs.nodejs_20
- name: checkout repository
uses: actions/checkout@v4
- name: run generator
run: nix-shell -p nixos-generators --run "nixos-generate -c inventory/demo-configuration.nix -f proxmox-lxc"

2
.gitignore vendored
View file

@ -1,4 +1,6 @@
.DS_Store
*.qcow2
result
node_modules
cache
dist

View file

@ -36,7 +36,7 @@ export default defineConfig({
{
text: 'Getting started',
items: [
{ text: 'Generate configuration', link: '/generate' },
{ text: 'Local installation', link: '/installation' },
{ text: 'Build virtual machine', link: '/build-virtual-machine' },
]
}

19
build-virtual-machine.md Normal file
View file

@ -0,0 +1,19 @@
# Build images based on your generated configurations
Your Nix configurations are located in the `inventory` folder you can build and run the configuration file you want by running nixos-generate from the NixiN root folder. If the build succeeds, the last output is a command located in your nix store to run your vm.
## Images formats
Check <https://github.com/nix-community/nixos-generators?tab=readme-ov-file#supported-formats> to find available formats.
For example, for qemu-kvm runner
```bash
nixos-generate -c inventory/demo-configuration.nix -f vm
```
(nixos-generate is installed by nix-shell, check `shell.nix` to see the packages added)
## Cross compile
Check <https://github.com/nix-community/nixos-generators?tab=readme-ov-file#cross-compiling>.

View file

@ -1,10 +1,77 @@
<script>
export default {
beforeMount() {
this.availableServices.forEach((s, i) => {
s.inBundle = []
})
this.availableBundles.forEach((b, i) => {
b.services.forEach((s) => {
this.availableServices.find(item => item.id === s).inBundle.push(b.id);
})
})
},
data() {
return {
netconf: 'autoconfig',
networkingHostname: '',
networkingDomain: 'distrilab.org',
networkingDomain: 'distrilab.eu',
availableBundles: [{
"id": "writeCollectively",
"name": "Write collectively : pads",
"services": [
'hedgedoc', 'nextcloud'
]
},
{
"id": "forge",
"name": "Forge : git repo, CI/CD workers, and NixiN",
"services": [
'forgejo', 'forgejoRunner', 'nixin'
]
},
{
"id": "socialMedia",
"name": "Social media: hosted social medias in activitypub web-apps",
"services": [
'gotosocial', 'peertube', 'lemmy'
]
}],
availableServices: [{
"id": "hedgedoc",
"name": "Hedgedoc : realtime collaborative markdown editor"
},
{
"id": "forgejo",
"name": "Forgejo : git hosting"
},
{
"id": "forgejoRunner",
"name": "Forgejo runner : CD/CI runner for Forgejo"
},
{
"id": "gotosocial",
"name": "Gotosocial : personal light activityPub social media"
},
{
"id": "peertube",
"name": "Peertube : video hosting platform with activityPub"
},
{
"id": "lemmy",
"name": "Lemmy : reddit alternative with activityPub"
},
{
"id": "nextcloud",
"name": "Nextcloud : personnal cloud"
},
{
"id": "nixin",
"name": "NixiN : web ui for configurations"
}],
nixinBundles: [],
nixinServices: [],
timezone: 'Etc/UTC',
locale: 'en_US.UTF-8',
user: 'operator',
@ -18,6 +85,13 @@ export default {
} else {
this.networkingDomain = ''
}
},
selectServices(services) {
services.forEach((s) => {
if (this.nixinServices.indexOf(s) === -1) {
this.nixinServices.push(s)
}
})
}
}
}
@ -31,27 +105,23 @@ export default {
<strong>Choose your network configuration</strong>
<label>
<input type="radio" v-model="netconf" name="netconf" value="autoconfig"
@click="netconfHasBeenChanged('autoconfig')">I'm a
noob in
network config, I trust
you to provide networking for me (ipv6 only)</label>
@click="netconfHasBeenChanged('autoconfig')">I'm a noob in network config, I trust you to provide networking
for me (ipv6 only)</label>
<label>
<input type="radio" v-model="netconf" name="netconf" value="publicip" @click="netconfHasBeenChanged">My server
has a public ip that I can
provide
has a public ip that I can provide
</label>
<label>
<input type="radio" v-model="netconf" name="netconf" value="localnetwork" @click="netconfHasBeenChanged">My
router is set so that my local
machine is accessible on the public network
router is set so that my local machine is accessible on the public network
</label>
<label>
<input type="radio" v-model="netconf" name="netconf" value="wireguard" @click="netconfHasBeenChanged">My server
can use a wireguard server i
can configure
can use a wireguard server i can configure
</label>
</div>
</div>
<div class="form-row">
<div class="form-cell">
<label>Machine network name</label>
@ -68,14 +138,33 @@ export default {
</div>
<h2>Usage bundles</h2>
<div class="form-row">
<div class="form-cell">
<strong>Choose your usage bundles (multiple choices possible if your machine can handle it)</strong>
<div v-for="bundle in availableBundles">
<label>
<input type="checkbox" v-model="nixinBundles" :id="bundle.id" :value="bundle.id"
@click="selectServices(bundle.services)" />
{{ bundle.name }}
</label>
</div>
</div>
</div>
<h2>Applications packages</h2>
<h2>Services</h2>
<div v-if="nixinBundles.length === 0">👆 Choose any upper bundle to make associated services appear.</div>
<div v-for="service in availableServices">
<label v-if="service.inBundle.some(ai => nixinBundles.includes(ai))">
<input type="checkbox" v-model="nixinServices" :id="service.id" :value="service.id" />
{{ service.name }}
</label>
</div>
<h2>Advanced configuration</h2>
Operating UNIX user name
Operating UNIX user password
Timezone
Locale
<h2>Other configuration</h2>
Operating UNIX user name<br />
Operating UNIX user password<br />
Timezone<br />
Locale<br />
<h2>Auto-generated configuration.nix file</h2>
<pre>
@ -87,9 +176,6 @@ export default {
./hardware-configuration.nix
];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
networking = {
hostName = "{{ networkingHostname }}";
domain = "{{ networkingDomain }}";
@ -136,6 +222,453 @@ export default {
time.timeZone = "{{ timezone }}";
i18n.defaultLocale = "{{ locale }}";
<div v-if="nixinServices.includes('gotosocial')">
{
services.gotosocial = {
enable = true;
setupPostgresqlDB = true;
settings = {
application-name = "My GoToSocial";
host = "gotosocial.example.com";
protocol = "https";
bind-address = "127.0.0.1";
port = 8080;
};
};
}
{
networking.firewall.allowedTCPPorts = [ 80 443 ];
services.nginx = {
enable = true;
clientMaxBodySize = "40M";
virtualHosts = with config.services.gotosocial.settings; {
"${host}" = {
enableACME = true;
forceSSL = true;
locations = {
"/" = {
recommendedProxySettings = true;
proxyWebsockets = true;
proxyPass = "http://${bind-address}:${toString port}";
};
};
};
};
};
}
</div>
<div v-if="nixinServices.includes('peertube')">
networking.extraHosts = ''
127.0.0.1 peertube.local
'';
environment.etc = {
"peertube/password-posgressql-db".text = "test123";
"peertube/password-redis-db".text = "test123";
};
services = {
peertube = {
enable = true;
localDomain = "peertube.local";
enableWebHttps = false;
database = {
host = "127.0.0.1";
name = "peertube_local";
user = "peertube_test";
passwordFile = "/etc/peertube/password-posgressql-db";
};
redis = {
host = "127.0.0.1";
port = 31638;
passwordFile = "/etc/peertube/password-redis-db";
};
settings = {
listen.hostname = "0.0.0.0";
instance.name = "PeerTube Test Server";
};
};
postgresql = {
enable = true;
enableTCPIP = true;
authentication = ''
hostnossl peertube_local peertube_test 127.0.0.1/32 md5
'';
initialScript = pkgs.writeText "postgresql_init.sql" ''
CREATE ROLE peertube_test LOGIN PASSWORD 'test123';
CREATE DATABASE peertube_local TEMPLATE template0 ENCODING UTF8;
GRANT ALL PRIVILEGES ON DATABASE peertube_local TO peertube_test;
ALTER DATABASE peertube_local OWNER TO peertube_test;
\connect peertube_local
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS unaccent;
'';
};
redis.servers.peertube = {
enable = true;
bind = "0.0.0.0";
requirePass = "test123";
port = 31638;
};
};
</div>
<div v-if="nixinServices.includes('lemmy')">
let
# add nginx reverse proxy and ACME web certificate
add_nginx = true;
nginx_ports = [ 80 443 ];
lemmy = {
upstreamName = "lemmy";
dataDir = "/var/lib/lemmy";
ip = "127.0.0.1";
port = 1234;
# TODO: Change this domain to your own
domain = "lemmy.example.com";
};
lemmy-ui = {
upstreamName = "lemmy-ui";
ip = "127.0.0.1";
port = 8536;
};
pict-rs = {
ip = "127.0.0.1";
port = 8080;
};
acmeDomain = lemmy.domain;
nginxVhost = lemmy.domain;
in {
security.acme = lib.mkIf add_nginx {
# TODO: change this to true if you accept
acceptTerms = false;
defaults = {
# TODO: you will receive a notification if automatic certificate renewal fails
email = "postmaster@${lemmy.domain}";
# TODO: put your dns provider here: https://go-acme.github.io/lego/dns/
dnsProvider = "";
# TODO: this file should contain environment variables expected by your dns provider
credentialsFile = "";
};
certs."${acmeDomain}" = {
domain = "${acmeDomain}";
};
};
networking.firewall.allowedTCPPorts = lib.mkIf add_nginx nginx_ports;
# is needed because of certificate file permissions
users.users.nginx.extraGroups = lib.mkIf add_nginx ["acme"];
services.nginx = lib.mkIf add_nginx {
upstreams."${lemmy.upstreamName}".servers."${lemmy.ip}:${builtins.toString lemmy.port}" = {};
upstreams."${lemmy-ui.upstreamName}".servers."${lemmy-ui.ip}:${builtins.toString lemmy-ui.port}" = {};
virtualHosts."${nginxVhost}" = {
useACMEHost = "${acmeDomain}";
# inherit from config.security.acme.acmeRoot;
acmeRoot = null;
# add redirects from http to https
forceSSL = true;
# this whole block was lifted from
https://github.com/LemmyNet/lemmy/blob/ef1aa18fd20cc03d492a81cb70cc75cf3281649f/docker/nginx.conf#L21 lines
21-32
extraConfig = ''
# disables emitting nginx version on error pages and in the Server response header field
server_tokens off;
gzip on;
gzip_types text/css application/javascript image/svg+xml;
gzip_vary on;
# Upload limit, relevant for pictrs
client_max_body_size 20M;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
'';
locations = {
"/" = {
extraConfig = ''
# distinguish between ui requests and backend
# don't change lemmy-ui or lemmy here, they refer to the upstream definitions on top
set $proxpass "http://${lemmy-ui.upstreamName}";
if ($http_accept = "application/activity+json") {
set $proxpass "http://${lemmy.upstreamName}";
}
if ($http_accept = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
set $proxpass "http://${lemmy.upstreamName}";
}
if ($request_method = POST) {
set $proxpass "http://${lemmy.upstreamName}";
}
proxy_pass $proxpass;
# Cuts off the trailing slash on URLs to make them valid
rewrite ^(.+)/+$ $1 permanent;
# Send actual client IP upstream
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
'';
};
# again, lifted wholesale from
https://github.com/LemmyNet/lemmy/blob/ef1aa18fd20cc03d492a81cb70cc75cf3281649f/docker/nginx.conf#L60 lines
60-69 (nice!)
"~ ^/(api|pictrs|feeds|nodeinfo|.well-known)" = {
proxyPass = "http://${lemmy.upstreamName}";
extraConfig = ''
# proxy common stuff
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
## Send actual client IP upstream
#proxy_set_header X-Real-IP $remote_addr;
#proxy_set_header Host $host;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
'';
};
};
};
};
systemd.services.lemmy-ui = {
environment = {
LEMMY_UI_HOST = lib.mkForce "${lemmy-ui.ip}:${toString lemmy-ui.port}";
LEMMY_UI_LEMMY_INTERNAL_HOST = lib.mkForce "${lemmy.ip}:${toString lemmy.port}";
LEMMY_UI_LEMMY_EXTERNAL_HOST = lib.mkForce lemmy.domain ;
LEMMY_UI_HTTPS="true";
};
};
services.pict-rs = {
enable = true;
port = pict-rs.port;
dataDir = "${dataDir}/pict-rs";
address = pict-rs.ip;
};
systemd.services.lemmy = {
requires = ["postgresql.service"];
after = ["postgresql.service"];
environment = {
LEMMY_DATABASE_URL = lib.mkForce "postgresql://lemmy@127.0.0.1:${toString
config.services.postgresql.port}/lemmy";
};
};
services.lemmy = {
enable = true;
ui.port = lemmy-ui.port;
database.createLocally = true;
settings = {
# TODO: Enable this much later when you tested everything.
# N.B. you can't change your domain name after enabling this.
federation.enabled = false;
# settings related to the postgresql database
database = {
user = "lemmy";
password = "secretlemmypassword";
host = "127.0.0.1";
port = ${config.services.postgresql.port};
database = "lemmy";
pool_size = 5;
};
# Pictrs image server configuration.
pictrs = {
# Address where pictrs is available (for image hosting)
url = "http://${pict-rs.ip}:${toString pict-rs.port}/";
# TODO: Set a custom pictrs API key. ( Required for deleting images )
api_key = "";
};
# TODO: Email sending configuration. All options except login/password are mandatory
email = {
# Hostname and port of the smtp server
smtp_server = "";
# Login name for smtp server
smtp_login = "";
# Password to login to the smtp server
smtp_password = "";
# Address to send emails from, eg "noreply@your-instance.com";
smtp_from_address = "noreply@${lemmy.domain}";
# Whether or not smtp connections should use tls. Can be none, tls, or starttls
tls_type = "none";
};
# TODO: Parameters for automatic configuration of new instance (only used at first start)
setup = {
# Username for the admin user
admin_username = "superawesomeadmin";
# Password for the admin user. It must be at least 10 characters.
admin_password = "";
# Name of the site (can be changed later)
site_name = "Lemmy at ${lemmy.domain}";
# Email for the admin user (optional, can be omitted and set later through the website)
admin_email = "admin@${lemmy.domain}";
};
# the domain name of your instance (mandatory)
hostname = lemmy.domain;
# Address where lemmy should listen for incoming requests
bind = lemmy.ip;
# Port where lemmy should listen for incoming requests
port = lemmy.port;
# Whether the site is available over TLS. Needs to be true for federation to work.
tls_enabled = true;
};
};
# needed for now
nixpkgs.config.permittedInsecurePackages = [
"nodejs-14.21.3"
"openssl-1.1.1t"
];
system.activationScripts."make_sure_lemmy_user_owns_files" = ''
uid='${config.users.users.lemmy.uid}';
gid='${config.users.groups.lemmy.gid}';
dir='${lemmy.dataDir}'
mkdir -p "''${dir}"
if [[ "$(${pkgs.toybox}/bin/stat "''${dir}" -c '%u:%g' | tee /dev/stderr )" != "''${uid}:''${gid}" ]]; then
chown -R "''${uid}:''${gid}" "''${dir}"
fi
'';
};
};
}
</div>
<div v-if="nixinServices.includes('nextcloud')">
services.nextcloud = {
enable = true;
hostName = "nextcloud.tld";
database.createLocally = true;
config = {
dbtype = "pgsql";
adminpassFile = "/path/to/admin-pass-file";
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
</div>
<div v-if="nixinServices.includes('hedgedoc')">
networking.firewall = {
allowedTCPPorts = [ 8001 ];
};
services.hedgedoc = {
enable = true;
settings.domain = "hedgedoc.nixin.local";
settings.port = 8001;
settings.host = "0.0.0.0";
settings.protocolUseSSL = false;
settings.allowOrigin = [
"localhost"
"hedgedoc.nixin.local"
];
};
</div>
<div v-if="nixinServices.includes('forgejoRunner')">
virtualisation.containers.enable = true;
virtualisation.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;
};
services.gitea-actions-runner = {
package = pkgs.forgejo-runner;
instances.default = {
enable = true;
name = "dromadaire";
url = "https://git.distrilab.fr";
# Obtaining the path to the runner token file may differ
tokenFile = "/etc/forgejo/runner.token";
labels = [
# provide a debian base with nodejs for actions
"debian-latest:docker://node:20-bookworm"
# fake the ubuntu name, because node provides no ubuntu builds
"ubuntu-latest:docker://node:20-bookworm"
# nixos
"nixos:docker://nixos/nix:latest"
# provide native execution on the host
#"native:host"
];
};
};
</div>
<div v-if="nixinServices.includes('forgejo')">
services.nginx = {
virtualHosts.${cfg.settings.server.DOMAIN} = {
forceSSL = true;
enableACME = true;
extraConfig = ''
client_max_body_size 512M;
'';
locations."/".proxyPass = "http://localhost:${toString srv.HTTP_PORT}";
};
};
services.forgejo = {
enable = true;
database.type = "postgres";
# Enable support for Git Large File Storage
lfs.enable = true;
settings = {
server = {
DOMAIN = "git.example.com";
# You need to specify this to remove the port from URLs in the web UI.
ROOT_URL = "https://${srv.DOMAIN}/";
HTTP_PORT = 3000;
};
# You can temporarily allow registration to create an admin user.
service.DISABLE_REGISTRATION = true;
# Add support for actions, based on act: https://github.com/nektos/act
actions = {
ENABLED = true;
DEFAULT_ACTIONS_URL = "github";
};
# Sending emails is completely optional
# You can send a test email from the web UI at:
# Profile Picture > Site Administration > Configuration > Mailer Configuration
mailer = {
ENABLED = true;
SMTP_ADDR = "mail.example.com";
FROM = "noreply@${srv.DOMAIN}";
USER = "noreply@${srv.DOMAIN}";
};
};
mailerPasswordFile = config.age.secrets.forgejo-mailer-password.path;
};
</div>
}
</code>
</pre>

23
installation.md Normal file
View file

@ -0,0 +1,23 @@
# Installation
## Requirements
For now, the NixiN installation process was just tested on a Linux distribution, on a computer with virtualisation capacities.
So only requirements are :
- A Linux system with virtualisation support
- With Nix installed <https://nix.dev/manual/nix/stable/installation/installation.html>
## Grab the code and run locally
Get the latest version from the official repository
```bash
git clone https://git.distrilab.fr/NixiN/nixin-web
```
Go in the main folder and run the `shell.nix` to install dependencies
```bash
cd nixin-web && nix-shell
```

View file

@ -0,0 +1,32 @@
{ config, pkgs, ... }:
{
virtualisation.vmVariant.virtualisation.forwardPorts = [
{ from = "host"; host.port = 8001; guest.port = 8001; }
];
networking.hosts = {
"127.0.0.1" = [ "hedgedoc.nixin.local" ];
};
networking.hostName = "demo";
#networking.firewall.enable = false;
networking.firewall = {
allowedTCPPorts = [ 8001 ];
};
services.hedgedoc = {
enable = true;
settings.domain = "hedgedoc.nixin.local";
settings.port = 8001;
settings.host = "0.0.0.0";
settings.protocolUseSSL = false;
settings.allowOrigin = [
"localhost"
"hedgedoc.nixin.local"
];
};
users.users.operator = {
isNormalUser = true;
extraGroups = [ "wheel" ];
initialPassword = "test";
};
system.stateVersion = "24.05";
}

4
package-lock.json generated
View file

@ -1,9 +1,11 @@
{
"name": "nixin-web",
"name": "NixiN",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "NixiN",
"license": "AGPL-3.0",
"devDependencies": {
"vitepress": "^1.3.3"
}

View file

@ -1,4 +1,11 @@
{
"name": "NixiN",
"repository": {
"type": "git",
"url": "git+https://git.distrilab.fr/NixiN/nixin-web.git"
},
"license": "AGPL-3.0",
"homepage": "https://nixin.distrilab.eu",
"scripts": {
"docs:dev": "vitepress dev",
"docs:build": "vitepress build",

14
shell.nix Normal file
View file

@ -0,0 +1,14 @@
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "nixin";
buildInputs = [
nodejs # for vitepress
nixos-generators # for building images
];
shellHook = ''
export PATH="$PWD/node_modules/.bin/:$PATH"
npm install
npm run
'';
}

View file

@ -1,28 +1,36 @@
# Technical principles
ToDo: intro on best practices that drive the technical choices
## KISS principle
"Keep it simple, stupid!"
## Do not reinvent the wheel
ToDo: nixos
ToDo: passwordstore
ToDo: krops
## There is only one timezone
Experience has shown that using multiple time-zones for the servers of an infrastructure is a recipe for disaster.
Also, using the timezone of one country for an international project is a source of confusion and headaches.
Especially when that timezone is subject to daylight saving changes that are causing the clock to jump 1 hour forward or backward twice a year.
The only sensible choice is to set the servers time to UTC and to transalte the timestamps to the user's timezone when displaying them.
The only sensible choice is to set the servers time to UTC and to transalte the timestamps to the user's timezone when displaying them on an interface.
This is strongly opinion based. And we may not not all agree on the subject. This is why we will make sure that it is easy for the users to choose their prefered timezone for setting up their servers.
This is strongly opinion based. We may not not all agree on the subject. This is why we will make sure that it is easy for the users to choose their prefered timezone for setting up their servers.
## Eat your own food
The project is bootstrapped using a hosting infrastructure thagtis based on Proxmox, Debian and YunoHost.
But the goal is to host the project using itself as soon as possible. That is using NixOS servers managed with the tools and principles developed by the NixiN project.
## Eat your own dog food
The project is bootstrapped using an infrastructure that is based on Proxmox, Debian and YunoHost for hosting its website and git forge.
Currently only the forgejo action runners used for CI/CD are hosted on NixOS servers.
But the goal is to host the whole project using itself as soon as possible. That is using NixOS servers managed with the tools and principles developed within the NixiN project.
## CI/CD
## Focus on user experience
## Prioritize security
ToDo: only open ports that are strictily necessary on the public interface. go through a VPN for everything else
ToDo: use fail2ban or reaction
ToDo: passwords manager
## No premature performance optimization
Use best practices to write efficient code but do not write overly complicated solutions based on a-priori thinking of performance issue.
@ -32,3 +40,9 @@ Only optimize what has been tested to be an issue.
Even though we think that Rust would be a better language for developing the tools of the project we are starting the first version using Go because it is faster to develop with it and easier to find contributors with this languages.
## ToDo
favor modern filesystems with snapshoting capability like zfs and btrfs
## To flake or not to flake?
There is a bit of controversy around flakes. They bring some intereting convenience when using NixOS and have spawned an extensive ecosystem. But they are not without drawbacks. We have decided to not use flakes for now. But we'll keep our architecture open for the users who want to use them.