summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Sima <ben@bsima.me>2022-02-23 22:37:15 -0500
committerBen Sima <ben@bsima.me>2022-02-23 22:37:15 -0500
commitcb34da30f3f699c1fcad71b80426e8d87886a2a5 (patch)
tree20796ae872060fd686046f90e0b9d0e8c53eb0dd
parent16fd30682fe0a619ea07fb9fbbd6bdfcaf2bed8c (diff)
Test out nixpert chat service
This is rough, I should move it up in the directory hierarchy and clean up the nix files, but that can all come later. Just gonna test it out for now. Will announce it tomorrow afternoon.
-rw-r--r--Biz/Cloud.nix1
-rw-r--r--Biz/Cloud/Web.nix13
-rw-r--r--Biz/Nixpert.md78
-rw-r--r--Biz/Nixpert/Chat.md123
-rw-r--r--Biz/Nixpert/Chat.nix191
5 files changed, 400 insertions, 6 deletions
diff --git a/Biz/Cloud.nix b/Biz/Cloud.nix
index 95d0150..f45cd20 100644
--- a/Biz/Cloud.nix
+++ b/Biz/Cloud.nix
@@ -15,6 +15,7 @@ bild.os {
./Cloud/Web.nix
./Cloud/Znc.nix
"${bild.sources.nixos-mailserver}"
+ ./Nixpert/Chat.nix
];
networking.hostName = "simatime";
networking.domain = "simatime.com";
diff --git a/Biz/Cloud/Web.nix b/Biz/Cloud/Web.nix
index fbe4e03..442024e 100644
--- a/Biz/Cloud/Web.nix
+++ b/Biz/Cloud/Web.nix
@@ -69,12 +69,13 @@ in
# the nginx/cgit module puts a '/' at the end of 'location', so we need to
# redirect '/git' to '/git/'
"/git".return = "301 https://$host/git/";
- "/" = {
- root = "/var/web/simatime.com";
- extraConfig = ''
- autoindex on;
- '';
- };
+ # disabled for nixpert test
+ #"/" = {
+ # root = "/var/web/simatime.com";
+ # extraConfig = ''
+ # autoindex on;
+ # '';
+ #};
# serve /~$USER paths
"~ ^/~(.+?)(/.*)?$" = {
alias = "/var/web/$1$2";
diff --git a/Biz/Nixpert.md b/Biz/Nixpert.md
new file mode 100644
index 0000000..d97b504
--- /dev/null
+++ b/Biz/Nixpert.md
@@ -0,0 +1,78 @@
+---
+title: Nixpert.chat biz plan
+---
+
+# Problem
+
+Nix is hard to use, especially hard to get started with. But the benefits are
+compounding for companies that do adopt it.
+
+The major pain point is getting help: devs often can't go to IRC because it's
+hard to use or they are prevented from doing so by confidential company
+information.
+
+# Solution
+
+We create a paid chat service where devs can quickly get answers to
+questions. We'll have a hosted chat client that is easy to use, maybe just use
+slack or something.
+
+# Key Metrics
+
+- Number of customers
+- Questions answered per shift
+- Hours of availability (24/7)
+
+# Unique Value Proposition
+
+## High-Level Concept
+
+Direct-line support for your infrastructure and build code. Like monadfix.com for Nix stuff.
+
+# Unfair Advantage
+
+- first mover
+
+# Channels
+
+- write articles on:
+ - common solutions
+ - benefits of nix
+ - highlight nix tool
+ - highlight nix function or technique
+
+# Customer Segments
+
+- crypto companies
+- ml companies
+
+## Early Adopters
+
+- startups, nix companies I know?
+
+# Cost Structure
+
+- hourly wages for staff
+- infrastructure costs
+ - chat server via prosody
+ - errbot for common questions?
+ - jitsi video chat
+ - hosted chat room via conversejs.org or JSXC
+ - chat clients (Dino, iOS: Trillian)
+
+# Revenue Streams
+
+- $500 - $1500 monthly subscription for companies
+- pair-programming sessions for added $150/hr
+
+# Growth plan
+
+## Unicorn Requirements
+
+### Sales Penetration
+
+## Support requirements
+
+### Tech Infra
+
+### Customer Support
diff --git a/Biz/Nixpert/Chat.md b/Biz/Nixpert/Chat.md
new file mode 100644
index 0000000..2f229af
--- /dev/null
+++ b/Biz/Nixpert/Chat.md
@@ -0,0 +1,123 @@
+---
+title: Professional Nix Chat Support
+header-includes: |
+ <link rel="stylesheet" type="text/css" media="screen" href="https://cdn.conversejs.org/9.0.0/dist/converse.min.css">
+ <script src="https://cdn.conversejs.org/9.0.0/dist/converse.min.js" charset="utf-8"></script>
+ <style>
+ </style>
+---
+
+[Nix](https://nixos.org) is a hermetic, deterministic, and declarative build system, package manager, and operating system. It will save you time and money by making sure:
+
+- your development environment is the same as your production environment
+- every build you do is definitive and reproducible
+- all your dependencies and environment variables are accounted for
+- developers never have to compile something twice - just download it from the cache
+
+But, you have to use it right. You can't go half-way in.
+
+Do you find Nix hard to use? Is the documentation confusing, the language obtuse and difficult? Have you had trouble training new devs?
+
+If so, you need this service.
+
+I'm offering dedicated Nix support for a limited number of clients. Here's how it works:
+
+- If you have a problem or question with Nix, NixOS, or Nixpkgs, send me a message
+- I will respond within an hour during business hours
+- I'll stay online with you until your problem is resolved
+- If we can't solve it via chat, we'll start a video call to work through it
+
+To sign up, say hello in the chat box in the corner to get started, or [register][] an account.
+
+<!--
+# What problems does Nix solve?
+
+<TODO/>
+
+# What benefits will I get by using Nix?
+
+<TODO/>
+
+- largest package repository in the world
+
+-->
+
+# Why buy as a team?
+
+Get a dedicated help room just for your team. Speed up your Nix development time for everyone. Accellerate your product development by getting the infrastructure questions out of the way.
+
+- $3000/month
+- ∞ Nix language questions
+- ∞ NixOS questions
+- ∞ Nixpkgs ecosystem questions
+- ∞ tooling support
+- 10h code review
+- + architecture review
+- + security review
+- + best practices
+
+# Why buy as an individual?
+
+Is Nix part of your job, but you don't feel 100% comfortable? Get fast dedicated help from an expert. Perform better at your job. Get your Nix questions answered before anyone else and get back to being productive.
+
+- $300/month
+- ∞ Nix language questions
+- ∞ NixOS questions
+- ∞ Nixpkgs ecosystem questions
+- ∞ tooling support
+- 2h code review
+u- + architecture review
+- + security review
+- + best practices
+
+# About this service
+
+This is just a private XMPP server, you can register an account [here][register] or use your own. Join the public [nix-lobby][] room to get started. When you sign up for the dedicated, paid support you'll be added to a private chat room that you can use for future help requests. We also have 1-on-1 and encrypted messaging for any sensitive information.
+
+# Who runs this?
+
+I'm [Ben Sima](https://bsima.me) and I've been working with Nix for 5+ years. All of my personal infrastructure runs on NixOS: email, IRC, XMPP, hardware, websites including this one. I've contributed open source packages and modules to nixpkgs. In my day job, I've managed a Nix-based build system and infrastructure for 150+ developers, handling dozens of custom packages, hundreds of builds per day, and a private cache of terabytes of Nix packages. I've probably managed the largest Nix deployment in the world besides the public NixOS.org infrastructure.
+
+# Why make this service?
+
+My career mission is to make reliable software, and Nix is one of the best tools for that job. But people often complain that Nix is hard to use. So my goal with this project is to make Nix easy to use and understand. First I will help you with your day-to-day problems. Along the way I will work out better ways to explain the concepts, benefits and usage of Nix. Then I will take these lessons back to the Nix manual and tooling to make the product better. So in buying this service your money actually buys twice the value: you get direct suport of your daily problems, and you get indirect support by improving Nix over time.
+
+The business manta I operate by is "win and help win." By offering this service I will help your organization win by improving your infrastructure and delivering reliable software products, and the Nix community wins by having more dedicated improvements contributed upstream.
+
+<!--
+
+# FAQ
+
+## Do you offer development or training?
+
+For special projects I offer Nix development work and training on a contract basis. Message me at [bsima@simatime.com](xmpp://bsima@simatime.com) and we'll see if your project is a good fit. If not, I can recommend other contractors that I trust will get the job done.
+
+## How do I manage my payment and account?
+
+It's all manual right now. I'll invoice you for payment at the beginning of every month. If you want to cancel, just message me, no hard feelings. Or just don't pay your invoice I guess.
+
+If you want your XMPP account deleted, you can usually do that from an XMPP client, or message me directly and I'll do it from the admin console.
+
+## Do you log our chats?
+
+Yeah I save the logs for 30 days. If you need them deleted for some reason, message me an I'll delete any logs. If you have sensitive data, use OMEMO or PGP encryption.
+
+-->
+
+[register]: https://simatime.com/chat
+[nix-lobby]: TODO
+
+<script>
+ // https://conversejs.org/demo/anonymous.html
+ converse.initialize({
+ allow_logout: false,
+ authentication: "anonymous",
+ auto_login: true,
+ auto_join_rooms: [ "nix-lobby@conference.simatime.com" ],
+ notify_all_room_messages: [ "nix-lobby@conference.simatime.com" ],
+ jid: "anon.simatime.com",
+ keepalive: true,
+ hide_muc_server: true,
+ bosh_service_url: "https://anon.simatime.com/http-bind"
+ });
+</script>
diff --git a/Biz/Nixpert/Chat.nix b/Biz/Nixpert/Chat.nix
new file mode 100644
index 0000000..2eae9d6
--- /dev/null
+++ b/Biz/Nixpert/Chat.nix
@@ -0,0 +1,191 @@
+{ config, pkgs, ... }:
+#
+# xmpp chat service
+#
+let
+ salespage = pkgs.runCommand "salespage" {} ''
+ mkdir -p $out
+ ${pkgs.pandoc}/bin/pandoc \
+ --standalone \
+ -f commonmark_x \
+ -t html ${./Chat.md} \
+ > $out/index.html
+ '';
+ ports = import ../Cloud/Ports.nix;
+ ssl = {
+ cert = "/var/lib/acme/simatime.com/fullchain.pem";
+ key = "/var/lib/acme/simatime.com/key.pem";
+ };
+in {
+ networking.firewall.allowedTCPPorts = [
+ # https://prosody.im/doc/ports
+ 5000 # file transfer
+ 5222 # client connections
+ 5269 # server-to-server
+ 5280 # http
+ 5281 # https
+ 5347 # external components
+ 5582 # telnet console
+ ];
+
+ services.prosody = {
+ enable = true;
+ package = pkgs.prosody.override {
+ withCommunityModules = [
+ "conversejs"
+ ];
+ };
+ # when i learn how to use security.acme better, and use separate certs, then i
+ # can fix this group
+ group = "nginx";
+ admins = [ "bsima@simatime.com" ];
+ allowRegistration = true;
+ inherit ssl;
+ uploadHttp = {
+ domain = "upload.simatime.com";
+ uploadExpireAfter = toString (60*60*24*30); # 30 days, as seconds
+ };
+ modules = {
+ announce = true;
+ bosh = true;
+ groups = true;
+ motd = true;
+ register = true;
+ server_contact_info = true;
+ vcard = true;
+ watchregistrations = true;
+ websocket = true;
+ welcome = true;
+ };
+ extraConfig = ''
+ conversejs_options = {
+ allow_registration = true;
+ --- authentication = "internal_plain";
+ bosh_service_url = "https://simatime.com/http-bind";
+ debug = true;
+ loglevel = "debug";
+ -- default_domain = "simatime.com";
+ -- domain_placeholder = "simatime.com";
+ -- jid = "simatime.com";
+ -- keepalive = true;
+ -- registration_domain = "simatime.com";
+ websocket_url = "wss://simatime.com/xmpp-websocket";
+ }
+
+ cross_domain_websocket = { "https://simatime.com", "https://anon.simatime.com" }
+ cross_domain_bosh = false; -- handle this with nginx
+ consider_bosh_secure = true;
+
+ -- this is a virtualhost that allows anonymous authentication. use this
+ -- for the sales lobby. the nix module doesn't support 'authentication'
+ -- so i have to do this here.
+ VirtualHost "anon.simatime.com"
+ authentication = "anonymous"
+ ssl = {
+ cafile = "/etc/ssl/certs/ca-bundle.crt";
+ key = "/var/lib/acme/simatime.com/key.pem";
+ certificate = "/var/lib/acme/simatime.com/fullchain.pem";
+ };
+ '';
+ muc = [
+ {
+ domain = "conference.simatime.com";
+ maxHistoryMessages = 10000;
+ name = "Chat Rooms";
+ restrictRoomCreation = "admin";
+ roomDefaultHistoryLength = 20;
+ roomDefaultMembersOnly = true;
+ roomDefaultModerated = true;
+ roomDefaultPublic = false;
+ }
+ ];
+ virtualHosts = {
+ "simatime.com" = {
+ domain = "simatime.com";
+ enabled = true;
+ inherit ssl;
+ };
+ };
+ };
+
+ services.nginx.virtualHosts."simatime.com".locations."/http-bind" = {
+ proxyPass = "https://simatime.com:5281/http-bind";
+ extraConfig = ''
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_buffering off;
+ add_header Access-Control-Allow-Origin "*";
+ '';
+ };
+
+ services.nginx.virtualHosts."simatime.com".locations."/" = {
+ root = "${salespage}";
+ extraConfig = ''
+ add_header Access-Control-Allow-Origin "*";
+ '';
+ };
+
+ services.nginx.virtualHosts."simatime.com".locations."/xmpp-websocket" = {
+ proxyPass = "https://simatime.com:5281/xmpp-websocket";
+ extraConfig = ''
+ proxy_http_version 1.1;
+ proxy_buffering off;
+ proxy_set_header Host $host;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_read_timeout 86400;
+ add_header Access-Control-Allow-Origin "*";
+ '';
+ };
+
+ services.nginx.virtualHosts."simatime.com".locations."/chat" = {
+ proxyPass = "https://simatime.com:5281/conversejs";
+ extraConfig = ''
+ add_header Access-Control-Allow-Origin "*";
+ '';
+ };
+
+ services.nginx.virtualHosts."anon.simatime.com" = {
+ useACMEHost = "simatime.com";
+ forceSSL = true;
+ locations = {
+ "/http-bind" = {
+ proxyPass = "https://anon.simatime.com:5281/http-bind";
+ extraConfig = ''
+ proxy_set_header Host $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_buffering off;
+ if ($request_method ~* "(GET|POST)") {
+ add_header Access-Control-Allow-Origin "*";
+ }
+ if ($request_method = OPTIONS) {
+ add_header Access-Control-Allow-Origin "*";
+ add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, HEAD";
+ add_header Access-Control-Allow-Headers "Authorization, Origin, X-Requested-With, Content-Type, Accept";
+ return 200;
+ }
+ '';
+ };
+ };
+ };
+
+ users.users.nginx.extraGroups = [ "prosody" ];
+
+ security.acme.certs.${config.networking.domain}.extraDomainNames = [
+ "upload.simatime.com" "conference.simatime.com" "simatime.com" "anon.simatime.com"
+ ];
+
+ #security.acme.certs.prosody = {
+ # domain = "${domain}";
+ # group = "prosody";
+ # dnsProvider = "rfc2136";
+ # #credentialsFile = config.secrets.files.dns_creds.path;
+ # postRun = "systemctl restart prosody";
+ # extraDomainNames = [
+ # domain
+ # "upload.${domain}"
+ # ];
+ #};
+}