From cb34da30f3f699c1fcad71b80426e8d87886a2a5 Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Wed, 23 Feb 2022 22:37:15 -0500 Subject: 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. --- Biz/Cloud.nix | 1 + Biz/Cloud/Web.nix | 13 ++-- Biz/Nixpert.md | 78 +++++++++++++++++++++ Biz/Nixpert/Chat.md | 123 +++++++++++++++++++++++++++++++++ Biz/Nixpert/Chat.nix | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 400 insertions(+), 6 deletions(-) create mode 100644 Biz/Nixpert.md create mode 100644 Biz/Nixpert/Chat.md create mode 100644 Biz/Nixpert/Chat.nix 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: | + + + +--- + +[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. + + + +# 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. + + + +[register]: https://simatime.com/chat +[nix-lobby]: TODO + + 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}" + # ]; + #}; +} -- cgit v1.2.3