Compare commits

...

8 commits

Author SHA1 Message Date
dea94a8bc8 feat: harmonize pre inr code templates
All checks were successful
deploy to prod / Build and deploy site (push) Successful in 49s
2024-10-15 10:45:44 +02:00
Florian Schmitt
9532ec6eff feat: use pre for code templates and add informations about template name 2024-10-15 11:29:50 +03:00
Florian Schmitt
81192c7b40 feat(configuration): harmonize demo and vue component for configuration 2024-10-11 13:51:41 +03:00
Florian Schmitt
b45617df8a refacto(components): new folders and custom folders feature (and little css optimisation) 2024-10-11 13:23:21 +03:00
Florian Schmitt
fb8296c081 refacto(services): per service form components 2024-10-10 13:45:58 +03:00
Florian Schmitt
1adbb1cd04 fix(components): forgejo runner no capital letter 2024-10-09 14:17:23 +03:00
Florian Schmitt
2c5305b5cd feat(components): wip form components 2024-10-09 14:05:43 +03:00
0d30926eeb update roadmap 2024-10-09 12:17:29 +02:00
25 changed files with 1294 additions and 1352 deletions

View file

@ -11,3 +11,42 @@
border-radius: 10em; border-radius: 10em;
} }
.form-cell {
margin-bottom: 1em;
}
.form-cell input[type="text"] {
border: 1px solid rgb(60, 60, 67);
display: block;
padding: 0.25em 0.5em;
border-radius: 0.25em;
min-width: 40em;
}
.form-cell input[type="text"]:focus {
border: 1px solid #0c78fc;
}
.nix-code {
white-space: pre-wrap;
}
.nix-code code {
margin: 0;
padding: 0;
width: 100%;
display: block;
}
.dynamic-component.code:before {
content: attr(data-name);
position: absolute;
color: blue;
top: -1.4em;
left: 0em;
font-size: 0.8em;
}
.dynamic-component.code {
position: relative;
border: blue 1px dotted;
padding: 1em;
margin: 1em 0;
white-space: pre-wrap;
}

View file

@ -1,6 +1,5 @@
# NixiN Web # NixiN Web
## Building the web site ## Building the web site
npm run docs:build npm run docs:build
@ -21,4 +20,4 @@ if you forked this repository, you need to create the secrets needed by the depl
- DEPLOY_USER : OS user to connect to production server - DEPLOY_USER : OS user to connect to production server
- DEPLOY_TARGET : sftp target where the web site has to be deployed, in the form of server.domain.tld:path - DEPLOY_TARGET : sftp target where the web site has to be deployed, in the form of server.domain.tld:path
- DEPLOY_SSH_PRIVATE_KEY : private ssh key used to authenticate with the server - DEPLOY_SSH_PRIVATE_KEY : private ssh key used to authenticate with the server
and configure the server witht the public key corresponding to DEPLOY_SSH_PRIVATE_KEY and configure the server with the public key corresponding to DEPLOY_SSH_PRIVATE_KEY

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,33 @@
<template>
<component :is="type" class="dynamic-component" :class="type.split('-')[1]" :data-name="type.split('-')[2]"></component>
</template>
<script>
let mod = []
// we autoload all components in form and nix-code folders
let comp = import.meta.glob('./{form,nix-code}/*.vue', { eager: true })
Object.entries(comp).forEach(([path, definition]) => {
let c = path.split('/');
const componentName = c[1]+'-'+c[2].replace(/\.\w+$/, '')
mod[componentName] = definition.default
})
// we autoload all custom components in form and nix-code custom folders
comp = import.meta.glob('../custom/components/{form,nix-code}/*.vue', { eager: true })
Object.entries(comp).forEach(([path, definition]) => {
let c = path.split('/');
const componentName = c[3]+'-'+c[4].replace(/\.\w+$/, '')
mod[componentName] = definition.default
})
export default {
components: {
...mod
},
props: {
type: { type: String, required: true },
},
}
</script>

12
components/NixCode.vue Normal file
View file

@ -0,0 +1,12 @@
<script setup>
import DynamicComponent from "./DynamicComponent.vue"
const props = defineProps(['service'])
let serviceComponent = 'nix-code-'+props.service
</script>
<template>
<dynamic-component :type="serviceComponent" />
</template>

13
components/NixForm.vue Normal file
View file

@ -0,0 +1,13 @@
<script setup>
import {provide} from 'vue';
import DynamicComponent from "./DynamicComponent.vue"
const props = defineProps(['service'])
let serviceComponent = 'form-'+props.service.id
provide('service', props.service)
</script>
<template>
<dynamic-component :type="serviceComponent" />
</template>

View file

@ -0,0 +1,11 @@
<script setup>
import { inject } from 'vue'
let nixin = inject('nixin')
const service = inject('service')
</script>
<template>
<label>
<input type="checkbox" v-model="nixin.services" :value="service.id" />
{{service.name}}
</label>
</template>

View file

@ -0,0 +1,11 @@
<script setup>
import { inject } from 'vue'
let nixin = inject('nixin')
const service = inject('service')
</script>
<template>
<label>
<input type="checkbox" v-model="nixin.services" :value="service.id" />
{{service.name}}
</label>
</template>

View file

@ -0,0 +1,11 @@
<script setup>
import { inject } from 'vue'
let nixin = inject('nixin')
const service = inject('service')
</script>
<template>
<label>
<input type="checkbox" v-model="nixin.services" :value="service.id" />
{{service.name}}
</label>
</template>

View file

@ -0,0 +1,11 @@
<script setup>
import { inject } from 'vue'
let nixin = inject('nixin')
const service = inject('service')
</script>
<template>
<label>
<input type="checkbox" v-model="nixin.services" :value="service.id" />
{{service.name}}
</label>
</template>

11
components/form/lemmy.vue Normal file
View file

@ -0,0 +1,11 @@
<script setup>
import { inject } from 'vue'
let nixin = inject('nixin')
const service = inject('service')
</script>
<template>
<label>
<input type="checkbox" v-model="nixin.services" :value="service.id" />
{{service.name}}
</label>
</template>

View file

@ -0,0 +1,11 @@
<script setup>
import { inject } from 'vue'
let nixin = inject('nixin')
const service = inject('service')
</script>
<template>
<label>
<input type="checkbox" v-model="nixin.services" :value="service.id" />
{{service.name}}
</label>
</template>

11
components/form/nixin.vue Normal file
View file

@ -0,0 +1,11 @@
<script setup>
import { inject } from 'vue'
let nixin = inject('nixin')
const service = inject('service')
</script>
<template>
<label>
<input type="checkbox" v-model="nixin.services" :value="service.id" />
{{service.name}}
</label>
</template>

View file

@ -0,0 +1,11 @@
<script setup>
import { inject } from 'vue'
let nixin = inject('nixin')
const service = inject('service')
</script>
<template>
<label>
<input type="checkbox" v-model="nixin.services" :value="service.id" />
{{service.name}}
</label>
</template>

View file

@ -0,0 +1,47 @@
<template>
<pre>
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;
};
</pre>
</template>

View file

@ -0,0 +1,36 @@
<template>
<pre>
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"
];
};
};
</pre>
</template>

View file

@ -0,0 +1,38 @@
<template>
<pre>
{
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}";
};
};
};
};
};
}
</pre>
</template>

View file

@ -0,0 +1,16 @@
<template>
<pre>
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"
];
};
</pre>
</template>

View file

@ -0,0 +1,239 @@
<template>
<pre>
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
'';
};
};
}
</pre>
</template>

View file

@ -0,0 +1,16 @@
<template>
<pre>
services.nextcloud = {
enable = true;
hostName = "nextcloud.tld";
database.createLocally = true;
config = {
dbtype = "pgsql";
adminpassFile = "/path/to/admin-pass-file";
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
</pre>
</template>

View file

@ -0,0 +1,62 @@
<template>
<pre>
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;
};
};
</pre>
</template>

0
custom/.gitkeep Normal file
View file

View file

@ -1,18 +1,16 @@
{ config, lib, pkgs, modulesPath, ... }: { pkgs, ... }:
{ {
#virtualisation.vmVariant.virtualisation.forwardPorts = [
# { from = "host"; host.port = 8001; guest.port = 8001; }
#];
networking.hosts = { networking.hosts = {
"127.0.0.1" = [ "hedgedoc.nixin.local" ]; "127.0.0.1" = [ "hedgedoc.nixin.local" ];
}; };
networking.hostName = "demo"; networking.hostName = "demo";
#networking.firewall.enable = false;
networking.firewall = { networking.firewall = {
allowedTCPPorts = [ 80 443 ]; allowedTCPPorts = [
80
443
];
}; };
services.hedgedoc = { services.hedgedoc = {
@ -22,8 +20,8 @@
settings.host = "0.0.0.0"; settings.host = "0.0.0.0";
settings.protocolUseSSL = false; settings.protocolUseSSL = false;
settings.allowOrigin = [ settings.allowOrigin = [
"localhost" "localhost"
"hedgedoc.nixin.local" "hedgedoc.nixin.local"
]; ];
}; };
@ -49,17 +47,15 @@
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL"; sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
virtualHosts."hedgedoc.nixin.local" = { virtualHosts."hedgedoc.nixin.local" = {
forceSSL = true; forceSSL = true;
enableACME = true; enableACME = true;
root = "/var/www/hedgedoc"; root = "/var/www/hedgedoc";
locations."/".proxyPass = "http://127.0.0.1:8001"; locations."/".proxyPass = "http://127.0.0.1:8001";
locations."/socket.io/" = { locations."/socket.io/" = {
proxyPass = "http://127.0.0.1:8001"; proxyPass = "http://127.0.0.1:8001";
proxyWebsockets = true; proxyWebsockets = true;
extraConfig = extraConfig = "proxy_ssl_server_name on;";
"proxy_ssl_server_name on;" };
;
};
}; };
}; };

703
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,17 +1,17 @@
# NixiN's roadmap # NixiN's roadmap
This project is still very young but the main steps are already identified. This project is still very young but the main steps are already identified.
The roadmap may move if priorities are evolving. The roadmap may move when priorities are evolving.
## v0.1 ## v0.1
**This version targets builds for simple mono-server configuration that can contain multiple webapps**. **This version targets builds for simple mono-server configuration that can contain multiple webapps**.
We are using [nixos-generators](https://github.com/nix-community/nixos-generators) to be able to build any type of container or vm, for any architecture. Use of [nixos-generators](https://github.com/nix-community/nixos-generators) to build images of any type of container or vm, for any architecture and installation ISO images.
The code is based on Vitepress, a static webapp that is used for documentation, and includes a dynamic component in vuejs for generating NixOS configuration files. The code is based on Vitepress, a static webapp that is used for documentation, and includes a dynamic component in vuejs for generating NixOS configuration files.
Nothing is saved server side, but the user must handler their configuration files by their own. Nothing is saved server side. The users must handler their configuration files on their own.
### Features ### Features