[Nix] Adds MCP config.

This commit is contained in:
2025-03-02 14:34:22 -08:00
parent 4c5ea117f9
commit 871a065ea8
24 changed files with 1062 additions and 16 deletions

View File

@@ -0,0 +1,89 @@
# Status: Far too complicated to set up right now. There's a lot of built-in
# assumptions about the database and a lot of services to connect to. I think
# they tried to open-source their production code, but it's not particularly
# generic right now.
#
# See https://github.com/AppFlowy-IO/AppFlowy-Cloud/blob/main/doc/DEPLOYMENT.md
{ config, pkgs, ... }:
let
inherit (import ./lib.nix config) mkContainer;
inherit (import ./secrets.nix) appflowy;
in
{
virtualisation.oci-containers.containers = {
appflowy = mkContainer {
image = "appflowyinc/appflowy_cloud:latest";
hostName = "appflowy";
dependsOn = [
"appflowy-gotrue"
"appflowy-db"
];
port = 80;
volumes = [];
environment = {
RUST_LOG = "info";
APPFLOWY_ENVIRONMENT = "production";
APPFLOWY_DATABASE_URL = "postgres://${appflowy.db.username}:${appflowy.db.password}@appflowy-db:5432/${appflowy.db.database}";
APPFLOWY_REDIS_URI = redis://valkey:6379;
APPFLOWY_GOTRUE_JWT_SECRET=appflowy.gotrue.jwt.secret;
APPFLOWY_GOTRUE_JWT_EXP = toString appflowy.gotrue.jwt.expiration;
APPFLOWY_GOTRUE_BASE_URL= "http://appflowy-gotrue:9999";
APPFLOWY_GOTRUE_EXT_URL = "http://appflowy-gotrue.havenisms.com";
APPFLOWY_GOTRUE_ADMIN_EMAIL = appflowy.gotrue.admin.email;
APPFLOWY_GOTRUE_ADMIN_PASSWORD = appflowy.gotrue.admin.password;
APPFLOWY_S3_USE_MINIO = "true";
APPFLOWY_S3_MINIO_URL= "https://minio.${config.domainName}";
APPFLOWY_S3_ACCESS_KEY = appflowy.s3.accessKey;
APPFLOWY_S3_SECRET_KEY = appflowy.s3.secretKey;
APPFLOWY_S3_BUCKET = appflowy.s3.bucket;
APPFLOWY_S3_REGION="us-east-1";
# APPFLOWY_MAILER_SMTP_HOST=${APPFLOWY_MAILER_SMTP_HOST}
# APPFLOWY_MAILER_SMTP_PORT=${APPFLOWY_MAILER_SMTP_PORT}
# APPFLOWY_MAILER_SMTP_USERNAME=${APPFLOWY_MAILER_SMTP_USERNAME}
# APPFLOWY_MAILER_SMTP_PASSWORD=${APPFLOWY_MAILER_SMTP_PASSWORD}
# APPFLOWY_ACCESS_CONTROL=${APPFLOWY_ACCESS_CONTROL}
# APPFLOWY_DATABASE_MAX_CONNECTIONS=${APPFLOWY_DATABASE_MAX_CONNECTIONS}
# APPFLOWY_AI_SERVER_HOST=${APPFLOWY_AI_SERVER_HOST}
# APPFLOWY_AI_SERVER_PORT=${APPFLOWY_AI_SERVER_PORT}
# APPFLOWY_OPENAI_API_KEY=${APPFLOWY_OPENAI_API_KEY}
};
homepageOpts = {
group = "Apps ";
name = "Appflowy";
icon = "appflowy.svg";
description = "Knowledge Base";
};
};
appflowy-db = {
image = "docker.io/postgres:16-alpine";
autoStart = true;
volumes = [
# TODO: move to faster storage?
"/tank/appflowy/db:/var/lib/postgresql/data"
"/tank/appflowy/migrations/before:/docker-entrypoint-initdb.d"
];
environment = {
POSTGRES_USER = appflowy.db.username;
POSTGRES_PASSWORD = appflowy.db.password;
POSTGRES_DB = appflowy.db.database;
};
extraOptions = [];
};
appflowy-gotrue = {
image = "appflowyinc/gotrue:latest";
autoStart = true;
dependsOn = [];
extraOptions = [];
volumes = [];
environment = {
GOTRUE_SITE_URL = "https://appflowy.havenisms.com";
GOTRUE_JWT_SECRET = appflowy.gotrue.jwt.secret;
GOTRUE_JWT_EXP = toString appflowy.gotrue.jwt.expiration;
GOTRUE_DB_DRIVER = "postgres";
API_EXTERNAL_URL = "http://appflowy-gotrue.havenisms.com";
DATABASE_URL = "postgres://supabase_auth_admin:root@appflowy-db:5432/${appflowy.db.database}";
PORT = "9999";
};
};
};
}

View File

@@ -0,0 +1,25 @@
{ config, pkgs, ... }:
let
inherit (import ./lib.nix config) mkContainer;
in {
virtualisation.oci-containers.containers.atomicserver = mkContainer {
image = "joepmeneer/atomic-server";
hostName = "atomic";
port = 80;
volumes = [
"/tank/atomicserver:/atomic-storage"
];
environment = {
ATOMIC_INITIALIZE = "true";
ATOMIC_SERVER_URL = "https://atomic.havenisms.com";
ATOMIC_DOMAIN = "atomic.havenisms.com";
ATOMIC_HTTPS = "false";
};
homepageOpts = {
group = "Apps";
name = "Atomic Server";
icon = "atomicserver.svg";
description = "Atomic Knowledge Management System";
};
};
}

View File

@@ -0,0 +1,22 @@
# Not in use, just reference.
{ config, pkgs, ... }:
let inherit (import ./lib.nix config) mkContainer; in
{
virtualisation.oci-containers.containers.baserow = mkContainer {
image = "baserow/baserow";
hostName = "baserow";
port = 80;
volumes = [
"/tank/baserow:/baserow/data"
];
environment = {
BASEROW_PUBLIC_URL = "https://baserow.havenisms.com";
};
homepageOpts = {
group = "Apps";
name = "Baserow";
icon = "baserow.svg";
description = "No-Code Databases";
};
};
}

View File

@@ -0,0 +1,14 @@
{ config, pkgs, ... }:
let inherit (import ./lib.nix config) mkContainer; in
{
virtualisation.oci-containers.containers.collabora = {
image = "collabora/code";
volumes = [
"/tank/config/collabora:/etc/coolwsd"
];
environment = {
DONT_GEN_SSL_CERT = "true";
};
autoStart = true;
};
}

View File

@@ -0,0 +1,30 @@
config:
let
hostRule = host: "Host(`${host}.${config.domainName}`)";
localNetRule = "ClientIP(`${config.localNet}`)";
localHostRule = host: "${localNetRule} && ${hostRule host}";
in
{
inherit hostRule localNetRule localHostRule;
mkContainer = { image, dependsOn ? [], hostName, port, volumes ? [], environment ? [], homepageOpts, public ? false}:
let routerRule = if public then hostRule hostName else localHostRule hostName;
in
{
image = image;
autoStart = true;
dependsOn = dependsOn;
extraOptions = [
"-l=traefik.enable=true"
"-l=traefik.http.routers.${hostName}.rule=${routerRule}"
"-l=traefik.http.services.${hostName}.loadbalancer.server.port=${toString port}"
"-l=homepage.group=${homepageOpts.group}"
"-l=homepage.name=${homepageOpts.name}"
"-l=homepage.icon=${homepageOpts.icon}"
"-l=homepage.href=https://${hostName}.${config.domainName}"
"-l=homepage.description=${homepageOpts.description}"
];
volumes = volumes;
environment = environment;
};
}

View File

@@ -0,0 +1,26 @@
{ config, pkgs, ... }:
let inherit (import ./lib.nix config) mkContainer; in
{
virtualisation.oci-containers.containers.mariadb = {
image = "mariadb:11";
autoStart = true;
extraOptions = [
];
volumes = [
"/tank/mariadb:/var/lib/mysql"
];
cmd = [
"--innodb-buffer-pool-size=512M"
"--transaction-isolation=READ-COMMITTED"
"--character-set-server=utf8mb4"
"--collation-server=utf8mb4_unicode_ci"
"--max-connections=512"
"--innodb-rollback-on-timeout=OFF"
"--innodb-lock-wait-timeout=120"
];
environment = {
MARIADB_DATABASE = "mariadb";
MARIADB_ROOT_PASSWORD = "root123";
};
};
}

View File

@@ -0,0 +1,34 @@
{ config, pkgs, ... }:
let
inherit (import ./lib.nix config) localHostRule;
inherit (import ./secrets.nix) minioAdminPassword;
in
{
virtualisation.oci-containers.containers.minio = {
image = "minio/minio";
autoStart = true;
volumes = [
"/tank/minio:/data"
];
cmd = [ "server" "/data" "--console-address" ":9001" ];
environment = {
MINIO_BROWSER_REDIRECT_URL = "https://console.minio.havenisms.com/";
MINIO_ROOT_USER = "minioadmin";
MINIO_ROOT_PASSWORD = minioAdminPassword;
};
extraOptions = [
"-l=traefik.enable=true"
"-l=traefik.http.routers.minio.rule=${localHostRule "minio"}"
"-l=traefik.http.routers.minio.service=minio"
"-l=traefik.http.services.minio.loadbalancer.server.port=9000"
"-l=traefik.http.routers.minio-console.rule=${localHostRule "console.minio"}"
"-l=traefik.http.routers.minio-console.service=minio-console"
"-l=traefik.http.services.minio-console.loadbalancer.server.port=9001"
"-l=homepage.group=Infra"
"-l=homepage.name=Minio"
"-l=homepage.icon=mino.svg"
"-l=homepage.href=https://minio-admin.${config.domainName}"
"-l=homepage.description=Reverse proxy"
];
};
}

View File

@@ -0,0 +1,29 @@
{ config, pkgs, ... }:
let inherit (import ./lib.nix config) hostRule; in
{
virtualisation.oci-containers.containers.nextcloud = {
image = "docker.io/library/nextcloud:latest";
extraOptions = [
"-l=traefik.enable=true"
"-l=traefik.http.routers.nextcloud.rule=${hostRule "cloud"}"
"-l=traefik.http.services.nextcloud.loadbalancer.server.port=80"
"-l=homepage.group=Apps"
"-l=homepage.name=NextCloud"
"-l=homepage.icon=nextcloud.png"
"-l=homepage.href=https://cloud.${config.domainName}"
"-l=homepage.description=Productivity suite"
"-l=homepage.widget.type=nextcloud"
"-l=homepage.widget.url=http://nextcloud:8080"
];
volumes = [
"/tank/nextcloud:/var/www/html"
];
environment = {
POSTGRES_HOST = "db";
POSTGRES_DB = "nextcloud";
POSTGRES_USER = "nextcloud";
POSTGRES_PASSWORD = "nextcloud123";
};
};
}

View File

@@ -0,0 +1,20 @@
{ config, pkgs, ... }:
let inherit (import ./lib.nix config) mkContainer; in
{
virtualisation.oci-containers.containers.prometheus = mkContainer {
image = "prom/prometheus";
hostName = "prometheus";
port = 9090;
volumes = [
"/tank/config/prometheus:/etc/prometheus"
];
environment = {
};
homepageOpts = {
group = "Infra";
name = "Prometheus";
icon = "prometheus.svg";
description = "Prometheus monitoring";
};
};
}

View File

@@ -0,0 +1,27 @@
{ config, pkgs, ... }:
let inherit (import ./lib.nix config) mkContainer; in
{
virtualisation.oci-containers.containers.searxng = mkContainer {
hostName = "search";
image = "docker.io/searxng/searxng:latest";
port = 8080;
public = true;
dependsOn = [
"valkey"
];
homepageOpts = {
group = "Apps";
name = "SearXNG";
icon = "searxng.svg";
description = "Web search proxy";
};
volumes = [
"/tank/config/searxng:/etc/searxng"
];
environment = {
SEARXNG_BASE_URL = "https://search.${config.domainName}";
SEARXNG_REDIS_URL = "redis://valkey:6379/0";
};
};
}

View File

@@ -0,0 +1,60 @@
{ config, pkgs, ... }:
let inherit (import ./lib.nix config) hostRule;
syncRule = "(PathPrefix(`/client/`) || PathPrefix(`/_matrix/client/unstable/org.matrix.msc3575/sync`))";
wellKnownRule = "PathPrefix(`/.well-known`)";
in
{
virtualisation.oci-containers.containers = {
synapse = {
image = "docker.io/matrixdotorg/synapse:latest";
autoStart = true;
dependsOn = [
"db"
];
volumes = [
"/tank/config/synapse/data:/data"
];
ports = [
"8008:8008/tcp"
];
extraOptions = [
"-l=traefik.enable=true"
"-l=traefik.http.routers.synapse.rule=${hostRule "chat"} && !(${syncRule} || ${wellKnownRule})"
"-l=traefik.http.services.synapse.loadbalancer.server.port=8008"
];
};
matrix_sliding_sync = {
image = "ghcr.io/matrix-org/sliding-sync:latest";
dependsOn = ["db"];
ports = [
"8009:8009"
];
environment = {
SYNCV3_SERVER = "http://synapse:8008";
# TODO: Store password securely
SYNCV3_DB = "postgres://syncv3:TZKr3RNmVx@db:5432/syncv3?sslmode=disable";
# TODO: Store secret securely
SYNCV3_SECRET = "4917590296b90910ec31ba355af6c7731409fd5f284d24912b852c3f928fa162";
SYNCV3_BINDADDR = ":8009";
};
extraOptions = [
"-l=traefik.enable=true"
"-l=traefik.http.routers.syncv3.rule=${hostRule "chat"} && ${syncRule}"
"-l=traefik.http.services.syncv3.loadbalancer.server.port=8009"
];
};
# This server helps to serve the .well-known files that are required by clients to find the sync server.
matrix_well_known = {
image = "nginx";
ports = [ "80" ];
volumes = [
"/tank/config/synapse/static-files:/usr/share/nginx/html:ro"
];
extraOptions = [
"-l=traefik.enable=true"
"-l=traefik.http.routers.matrix-static.rule=${hostRule "chat"} && ${wellKnownRule}"
"-l=traefik.http.services.matrix-static.loadbalancer.server.port=80"
];
};
};
}