add initial flake

This commit is contained in:
happysalada 2021-07-02 15:09:11 +09:00
parent aa7aa73d05
commit 279ec900a2
8 changed files with 323 additions and 6 deletions

2
.envrc
View file

@ -1 +1 @@
use_nix
use_flake

3
.gitignore vendored
View file

@ -62,4 +62,5 @@ deps.path*
.nix-hex/
.nix-mix/
.direnv/
.bash_history
.bash_history
result

View file

@ -169,6 +169,77 @@ Caddyserver and other servers can handle generating and setting up HTTPS certifi
---
### Option C with nixos
this repo is a flake and includes a nixos module.
Here are the detailed steps to deploy it.
- add it as an input to your system flake.
- add an overlay to make the package available
- add the required configuration in your system
Your flake.nix file would look like the following. Remember to replace myHostName with your actual hostname or however your deployed system is called.
```nix
{
inputs.bonfire.url = "github:happysalada/bonfire-app/main";
outputs = { self, nixpkgs, bonfire }: {
overlay = final: prev: with final;{
# a package named bonfire already exists on nixpkgs so we put it under a different name
elixirBonfire = bonfire.defaultPackage.x86_64-linux;
};
nixosConfigurations.myHostName = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
{
environment.systemPackages = [ agenix.defaultPackage.x86_64-linux ];
nixpkgs.overlays = [ self.overlay ];
}
./myHostName.nix
bonfire.nixosModules.bonfire
];
};
};
}
```
then in myHostName.nix would look like the following
TODO: add the caddy config
```nix
{ config, lib, pkgs, ... }:
{
services.bonfire = {
# you will need to expose bonfire with a reverse proxy, for example caddy
port = 4000;
package = pkgs.elixirBonfire;
dbName = "bonfire";
# the environment should contain a minimum of
# SECRET_KEY_BASE
# SIGNING_SALT
# ENCRYPTION_SALT
# RELEASE_COOKIE
# have a look into nix/module.nix for more details
# the way to deploy secrets is beyond this readme, but I would recommend agenix
environmentFile = "/run/secrets/bonfireEnv";
dbSocketDir = "/var/run/postgresql";
};
# this is uniquely for database backup purposes
# replace myBackupUserName with the user name that will do the backups
# if you want to do backups differently, feel free to remove this part of the config
services.postgresql = {
ensureDatabases = [ "bonfire" ];
ensureUsers = [{
name = "myBackupUserName";
ensurePermissions = { "DATABASE bonfire" = "ALL PRIVILEGES"; };
}];
};
}
```
## Step 3 - Run
By default, the backend listens on port 4000 (TCP), so you can access it on http://localhost:4000/ (if you are on the same machine). In case of an error it will restart automatically.

25
flake.lock Normal file
View file

@ -0,0 +1,25 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1622253036,
"narHash": "sha256-HSVusps0KHjVayUkWvFPiIZe1JKxT+GeDQBzcpw+MFE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "25bca77c48ddb0bacdb46e7398d948a348d06119",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

33
flake.nix Normal file
View file

@ -0,0 +1,33 @@
{
description = "Bonfire!";
outputs = { self, nixpkgs }:
let
# taken from https://github.com/ngi-nix/project-template/blob/master/flake.nix
# System types to support.
supportedSystems = [ "x86_64-linux" "x86_64-darwin" ];
# Helper function to generate an attrset '{ x86_64-linux = f "x86_64-linux"; ... }'.
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system);
# Nixpkgs instantiated for supported system types.
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; overlays = [ self.overlay ]; });
in
{
overlay = final: prev: {
bonfire = import ./nix/package.nix { pkgs = final; inherit self; };
};
packages = forAllSystems (system:
{
inherit (nixpkgsFor.${system}) bonfire;
});
defaultPackage = forAllSystems (system: self.packages.${system}.bonfire);
nixosModules.bonfire = import ./nix/module.nix;
devShell = forAllSystems
(system:
import ./nix/shell.nix {
pkgs = nixpkgsFor.${system};
}
);
};
}

104
nix/module.nix Normal file
View file

@ -0,0 +1,104 @@
{ pkgs, config, lib, ... }:
with lib;
let
bonfireConfig = config.services.bonfire;
in
{
options.services.bonfire = {
port = mkOption {
type = types.port;
default = 4000;
description = "port to run the instance on";
};
package = mkOption {
type = types.package;
description = "package to run the instance with";
};
hostname = mkOption {
type = types.str;
default = "bonfire.cafe";
example = "bonfire.cafe";
description = ''
hostname for which the service will be run
'';
};
dbName = mkOption {
type = types.str;
default = "bonfire";
description = ''
name of the database you want to connect to
'';
};
dbSocketDir = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
If this is defined, bonfire will connect to postgres
with a unix socket and not TCP/IP
'';
};
environmentFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
environment file for secret environment variables
should contain
SECRET_KEY_BASE
SIGNING_SALT
ENCRYPTION_SALT
RELEASE_COOKIE
'';
};
};
config = with bonfireConfig; {
services.postgresql = {
extraPlugins = with pkgs.postgresql_13.pkgs; [ postgis ];
ensureDatabases = [ dbName ];
ensureUsers = [{
# Same name as the unix user is needed
name = "bonfire";
ensurePermissions = { "DATABASE ${dbName}" = "ALL PRIVILEGES"; };
}];
};
systemd.services.bonfire = {
wantedBy = [ "multi-user.target" ];
after = [ "postgresql.service" ];
requires = [ "postgresql.service" ];
description = "Bonfire!";
serviceConfig = {
Type = "exec";
Restart = "on-failure";
RestartSec = 5;
ExecStartPre = "${package}/bin/bonfire eval Bonfire.Repo.ReleaseTasks.migrate";
ExecStart = "${package}/bin/bonfire start";
ExecStop = "${package}/bin/bonfire stop";
DynamicUser = true;
StateDirectory = "bonfire";
EnvironmentFile = environmentFile;
PrivateTmp = true;
ProtectSystem = "full";
NoNewPrivileges = true;
ReadWritePaths = "${if dbSocketDir == null then "" else dbSocketDir} /var/lib/bonfire";
};
environment = {
RELEASE_TMP = "/tmp";
TZDATA_DIR = "/var/lib/bonfire";
LANG = "en_US.UTF-8";
PORT = toString port;
POSTGRES_USER = "bonfire";
POSTGRES_DB = dbName;
POSTGRES_SOCKET_DIR = lib.mkIf (dbSocketDir != null) dbSocketDir;
HOSTNAME = hostname;
WITH_DOCKER = "no";
FLAVOUR = "reflow";
BONFIRE_FLAVOUR = "flavours/reflow";
};
};
};
}

75
nix/package.nix Normal file
View file

@ -0,0 +1,75 @@
{ pkgs, self, flavour ? "reflow" }:
let
beamPackages = with pkgs; beam.packagesWith beam.interpreters.erlang;
in
beamPackages.mixRelease rec {
pname = "bonfire";
version = "1.0.0";
mixEnv = "prod";
src = self;
# TODO make these configurable
BONFIRE_FLAVOUR = "flavours/${flavour}";
FLAVOUR = flavour;
mixFodDeps = beamPackages.fetchMixDeps {
pname = "mix-deps-${pname}";
inherit src mixEnv version;
LANG = "en_US.UTF-8";
inherit BONFIRE_FLAVOUR FLAVOUR;
# override needed here since bonfire dependencies rely on git
installPhase = ''
runHook preInstall
mix deps.get --only ${mixEnv}
cp -r --no-preserve=mode,ownership,timestamps $TEMPDIR/deps $out
runHook postInstall
'';
# TODO add sha256
# since I didn't know exactly what dependencies where being pulled
# I went for the quick hack of not checking for dependency integrity
# This has the downside of triggering a rebuild on every deployment
sha256 = null;
};
frontendAssets = with pkgs; stdenvNoCC.mkDerivation {
pname = "frontend-assets-${pname}";
nativeBuildInputs = [ nodejs cacert git elixir ];
inherit version src;
configurePhase = ''
export HOME=$(mktemp -d)
cp -r ${mixFodDeps} ./deps
chmod +w -R deps
mix js.deps.get
'';
buildPhase = ''
mix js.release
'';
installPhase = ''
cp -r priv/static $out
'';
outputHashAlgo = "sha256";
outputHashMode = "recursive";
# TODO add sha256
# since I didn't know exactly what dependencies where being pulled
# I went for the quick hack of not checking for dependency integrity
# This has the downside of triggering a rebuild on every deployment
outputHash = null;
impureEnvVars = lib.fetchers.proxyImpureEnvVars;
};
nativeBuildInputs = with pkgs; [ rustc cargo gcc ]; # for NIFs
postBuild = ''
cp -r ${frontendAssets} priv/static
# digest needs to write files
chmod -R u+w priv/static
mix phx.digest
'';
}

View file

@ -1,4 +1,4 @@
{ pkgs ? import <nixpkgs> { } }:
{ pkgs, flavour ? "reflow" }:
with pkgs;
@ -13,14 +13,14 @@ let
rev = "8421d5ee91b120f1fe78fe8b123fc0fdf59609ff";
sha256 = "sha256-MniXkng8v30xzSC+cIZ+K6DWeJLCFDieXZioAQFU4/s=";
};
cargoSha256 = "sha256-z8SdQKME9/6O6ZRkNRI+vYZSf6fxAG4lz0Muv7876fY=";
cargoSha256 = "sha256-K4Wq949DK3STwKo0MgaGNsu3r+qg8OqqXK3O4g4FpR0=";
};
# define packages to install with special handling for OSX
shellBasePackages = [
git
beam.packages.erlang.elixir_1_11
nodejs-15_x
beam.packages.erlang.elixir_1_12
nodejs-16_x
postgresql_13
messctl
# for NIFs
@ -51,6 +51,14 @@ let
# elixir
export MIX_ENV=dev
export FORK=./forks
# bonfire
export FLAVOUR=${flavour}
export BONFIRE_FLAVOUR=flavours/${flavour}
export WITH_DOCKER=no
mix deps.get
mix js.deps.get
'';
in