Add FreeBSD packaging

This commit is contained in:
Harshad Sharma 2024-05-13 20:56:07 +05:30
parent ca74091335
commit 6cbcd313ee
13 changed files with 203 additions and 54 deletions

7
.gitignore vendored
View file

@ -27,6 +27,11 @@ freedive-*.tar
# Ignore assets that are produced by build tools.
/priv/static/assets/
/priv/static/favicon-*.*
/priv/static/robots-*.*
/priv/static/robots.txt.gz
/priv/static/images/logo-*.*
/priv/static/images/logo.svg.gz
# Ignore digested assets cache.
/priv/static/cache_manifest.json
@ -39,3 +44,5 @@ npm-debug.log
*.db
*.db-*
# FreeBSD package
*.pkg

View file

@ -7,15 +7,6 @@ import Config
# any compile-time configuration in here, as it won't be applied.
# The block below contains prod specific runtime configuration.
# ## Using releases
#
# If you use `mix release`, you need to explicitly enable the server
# by passing the PHX_SERVER=true when you start it:
#
# PHX_SERVER=true bin/freedive start
#
# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server`
# script that automatically sets the env var above.
if System.get_env("PHX_SERVER") do
config :freedive, FreediveWeb.Endpoint, server: true
end
@ -50,55 +41,26 @@ if config_env() == :prod do
You can generate one by calling: mix phx.gen.secret
"""
host = System.get_env("PHX_HOST") || "example.com"
port = String.to_integer(System.get_env("PORT") || "4000")
# config :freedive, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")
host = System.get_env("HOST") || "localhost"
bind = System.get_env("BIND") || "local4"
port = String.to_integer(System.get_env("PORT") || "5443")
ip = PhxConfigUtil.BindToIp.parse!(bind)
config :freedive, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")
config :freedive, FreediveWeb.Endpoint,
url: [host: host, port: 443, scheme: "https"],
http: [
# Enable IPv6 and bind on all interfaces.
# Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access.
# See the documentation on https://hexdocs.pm/bandit/Bandit.html#t:options/0
# for details about using IPv6 vs IPv4 and loopback vs public addresses.
ip: {0, 0, 0, 0, 0, 0, 0, 0},
port: port
url: [host: host, port: port, scheme: "https"],
https: [
ip: ip,
port: port,
cipher_suite: :strong,
keyfile: System.get_env("TLS_KEY_PATH"),
certfile: System.get_env("TLS_CERT_PATH")
],
secret_key_base: secret_key_base
# ## SSL Support
#
# To get SSL working, you will need to add the `https` key
# to your endpoint configuration:
#
# config :freedive, FreediveWeb.Endpoint,
# https: [
# ...,
# port: 443,
# cipher_suite: :strong,
# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
# certfile: System.get_env("SOME_APP_SSL_CERT_PATH")
# ]
#
# The `cipher_suite` is set to `:strong` to support only the
# latest and more secure SSL ciphers. This means old browsers
# and clients may not be supported. You can set it to
# `:compatible` for wider support.
#
# `:keyfile` and `:certfile` expect an absolute path to the key
# and cert in disk or a relative path inside priv, for example
# "priv/ssl/server.key". For all supported SSL configuration
# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1
#
# We also recommend setting `force_ssl` in your config/prod.exs,
# ensuring no data is ever sent via http, always redirecting to https:
#
# config :freedive, FreediveWeb.Endpoint,
# force_ssl: [hsts: true]
#
# Check `Plug.SSL` for all available options in `force_ssl`.
# ## Configuring the mailer
#
# In production you need to configure the mailer to use a different adapter.

18
freedive.env.sample Normal file
View file

@ -0,0 +1,18 @@
# Web server
HOST="localhost"
BIND="local4"
PORT=3443
TLS_KEY_PATH="<%= @data_dir %>/tls.key"
TLS_CERT_PATH="<%= @data_dir %>/tls.crt"
# Cluster
# DNS_CLUSTER_QUERY=""
# Features
REGISTER_ACCOUNT_ENABLE="false"
# Phoenix
PHX_SERVER=true
SECRET_KEY_BASE="CHANGE-ME"
DATABASE_PATH="<%= @data_dir %>/freedive.db"

25
mix.exs
View file

@ -5,11 +5,21 @@ defmodule Freedive.MixProject do
[
app: :freedive,
version: "0.1.0",
description: "Dive into FreeBSD",
homepage_url: "https://brew.bsd.cafe/hiway/freedive",
maintainer: "harshad@sharma.io",
elixir: "~> 1.14",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps()
deps: deps(),
freebsd_pkg: freebsd_pkg()
]
end
defp freebsd_pkg do
[
service_commands: ["init", "account_register", "password_reset"],
]
end
@ -61,7 +71,9 @@ defmodule Freedive.MixProject do
{:bandit, "~> 1.2"},
{:phx_tailwind_freebsd, "~> 0.2.1", runtime: Mix.env() == :dev},
{:lucide_icons, "~> 1.1"},
{:phx_component_helpers, "~> 1.4"}
{:phx_component_helpers, "~> 1.4"},
{:mix_freebsd_pkg, github: "hiway/mix_freebsd_pkg", runtime: Mix.env() == :dev},
{:phx_config_util, "~> 0.1.0"}
]
end
@ -89,7 +101,14 @@ defmodule Freedive.MixProject do
"tailwind freedive --minify",
"esbuild freedive --minify",
"phx.digest"
]
],
package: ["compile", "assets.deploy", "release --overwrite", "freebsd.pkg"]
]
end
def cli do
[
preferred_envs: [package: :prod]
]
end
end

View file

@ -24,8 +24,11 @@
"lucide_icons": {:hex, :lucide_icons, "1.1.1", "39e3ea54b554edd9253c2d9949a6171cd54609c86d9848d315ca9dd3c148e459", [:mix], [{:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.20", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "93c4c87bfc1080e159a43d81a494d1bb93c6f59c127bfc108f39158e6b77c4c2"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mint": {:hex, :mint, "1.6.0", "88a4f91cd690508a04ff1c3e28952f322528934be541844d54e0ceb765f01d5e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "3c5ae85d90a5aca0a49c0d8b67360bbe407f3b54f1030a111047ff988e8fefaa"},
"mix_freebsd_pkg": {:git, "https://github.com/hiway/mix_freebsd_pkg.git", "4940f1a85a4951c2a16b21d8302b3df0c2c1cabc", []},
"net_address": {:hex, :net_address, "0.3.1", "70832e5a35a2c9f2d6e5bcf43e3164b9c4f7515ca7cc8740d2d38aab39ffa0e9", [:mix], [], "hexpm", "eb20da348f1ad88fdfaaa4e8923a3906ac54b54cb67ac1731f86bce07cb2b081"},
"nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
"opus": {:hex, :opus, "0.8.4", "9de6d0eb1b3bad69442059b54d473cf25fa3ea32905f3022eb5e892aff1c4a2f", [:mix], [{:retry, "~> 0.8", [hex: :retry, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "431b5361ac34af5d72921a5c9a09f4f61c3d0911e7de636af982bb5915a41c5e"},
"phoenix": {:hex, :phoenix, "1.7.12", "1cc589e0eab99f593a8aa38ec45f15d25297dd6187ee801c8de8947090b5a9d3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "d646192fbade9f485b01bc9920c139bfdd19d0f8df3d73fd8eaf2dfbe0d2837c"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.5.1", "6fdbc334ea53620e71655664df6f33f670747b3a7a6c4041cdda3e2c32df6257", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ebe43aa580db129e54408e719fb9659b7f9e0d52b965c5be26cdca416ecead28"},
"phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"},
@ -35,9 +38,11 @@
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
"phx_component_helpers": {:hex, :phx_component_helpers, "1.4.1", "dbbc8ed3082055a901e3918cb24ec43df64f0f3bb81d6865beaf114fb355569e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, ">= 4.0.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, ">= 0.18.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "cf499d28f2af3c8398230994c54d2ea86cd4759523693b6b75b9897cc7f57912"},
"phx_config_util": {:hex, :phx_config_util, "0.1.0", "185e3435e8fa0d18113d153ce6d40cc7e865ee7f1dfd27e66b76bc612ed681fd", [:mix], [{:net_address, "~> 0.3.1", [hex: :net_address, repo: "hexpm", optional: false]}], "hexpm", "fe0d303d9716875f4d586a706d39caf4a374dafb0e0adff63dd1e0cd25117133"},
"phx_tailwind_freebsd": {:hex, :phx_tailwind_freebsd, "0.2.1", "23583bb200196f879fbedd49be69b4d2d7ad2137971ad9a060f2cf38358c14a8", [:mix], [], "hexpm", "04aabe4b93ba850ca9116ba0a0cf302cbc5b846d09d0e268213a4553a9c53b31"},
"plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"},
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
"retry": {:hex, :retry, "0.18.0", "dc58ebe22c95aa00bc2459f9e0c5400e6005541cf8539925af0aa027dc860543", [:mix], [], "hexpm", "9483959cc7bf69c9e576d9dfb2b678b71c045d3e6f39ab7c9aa1489df4492d73"},
"swoosh": {:hex, :swoosh, "1.16.5", "5742f24c4d081671ebe87d8e7f6595cf75205d7f808cc5d55b09e4598b583413", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.1.0", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b2324cf696b09ee52e5e1049dcc77880a11fe618a381e2df1c5ca5d69c380eb0"},
"tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},

View file

@ -0,0 +1 @@
#!/bin/sh

View file

@ -0,0 +1 @@
#!/bin/sh

View file

@ -0,0 +1 @@
#!/bin/sh

View file

@ -0,0 +1,24 @@
#!/bin/sh
ensure_user() {
group=$1
user=$1
if pw groupshow $group 2>/dev/null; then
echo "Group '$group' already exists."
else
echo "Creating group '$group'."
pw groupadd $group
fi
if id $user 2>/dev/null; then
echo "User '$user' already exists."
else
echo "Creating user '$user' with group '$group'."
pw useradd $user -g $group -s /usr/sbin/nologin -d /nonexistent
fi
}
<%= if @user != "root" do %>
ensure_user "<%= @user %>" "<%= @user %>"
<% end %>

View file

@ -0,0 +1,57 @@
#!bin/sh
# PROVIDE: <%= @name %>
# REQUIRE: LOGIN
# REQUIRE: DAEMON
<%= @name %>_enable=${<%= @name %>_enable:-"NO"}
. /etc/rc.subr
: ${<%= @name %>_env_file:="<%= @env_file %>"}
name="<%= @name %>"
<%= @name %>_user="<%= @user %>"
<%= @name %>_group="<%= @group %>"
rcvar="<%= @name %>_enable"
command="<%= @app_dir %>/bin/<%= @name %>"
pidfile="<%= @run_dir %>/<%= @name %>.pid"
confdir="<%= @conf_dir %>"
logfile="<%= @log_dir %>/<%= @name %>.log"
extra_commands="<%= Enum.join(@service_commands, " ") %>"
procname=${command}
start_cmd="<%= @name %>_start"
stop_cmd="${command} stop"
<%= for cmd <- @service_commands do %>
<%= cmd %>_cmd="<%= @app_dir %>/<%= cmd %>.sh"
<% end %>
<%= @name %>_start() {
# Stop here if not running as root
if [ `id -u` -ne 0 ]; then
echo "You must be root to start <%= @name %>"
return 1
fi
: "${ERL_CRASH_DUMP:="<%= @run_dir %>/erl_crash.dump"}"
export ERL_CRASH_DUMP
if [ -f ${pidfile} ]; then
echo "Pidfile ${pidfile} exists. Is <%= @name %> running?"
return 1
fi
if [ -f ${ERL_CRASH_DUMP} ]; then
echo "Removing old crash dump file ${ERL_CRASH_DUMP}"
rm -f ${ERL_CRASH_DUMP}
fi
echo "Starting <%= @name %> as user <%= @user %>"
echo "Logs will be written to ${logfile}"
daemon -t ${name} -p ${pidfile} -f -H -o ${logfile} -u <%= @user %> ${command} start
}
load_rc_config ${name}
run_rc_command "$1"

View file

@ -0,0 +1,4 @@
#!/bin/sh
# account_register
<%= @app_dir %>/bin/<%= @name %> eval "Freedive.Release.account_create"

View file

@ -0,0 +1,46 @@
#!/bin/sh
if [ -f <%= @data_dir %>/tls.key ] ; then
echo "[ok] TLS keys for https endpoint"
else
echo "[create] TLS keys for https endpoint"
cat > <%= @data_dir %>/request.txt <<INNER_EOF
[req]
default_bits = 4096
default_md = sha256
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = NA
ST = NA
L = NA
O = NA
OU = NA
CN = <%= @name %>.local
[v3_req]
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = <%= @name %>.local
DNS.2 = localhost
IP.1 = 127.0.0.1
INNER_EOF
openssl req -new -nodes -x509 -days 36500 -newkey rsa:2048 -keyout <%= @data_dir %>/tls.key -out <%= @data_dir %>/tls.crt -config <%= @data_dir %>/request.txt
rm <%= @data_dir %>/request.txt
chown -R <%= @user %>:<%= @group %> <%= @data_dir %>
fi
# Check if the secret-key is already set in @env_file
if grep -q "CHANGE-ME" <%= @env_file %> ; then
echo "[create] Secret-key for web server"
SECRET_KEY="$( openssl rand -base64 128 | strings | grep -o '[[:alnum:]]' | head -n 64 | tr -d '\n'; echo )"
sed -i '' -e "s/CHANGE-ME/${SECRET_KEY}/g" <%= @env_file %>
else
echo "[ok] Secret-key for web server"
fi
# Migrate database
echo "[migrate] Database"
<%= @app_dir %>/bin/<%= @name %> eval "Freedive.Release.migrate"

View file

@ -0,0 +1,4 @@
#!/bin/sh
# password_reset
<%= @app_dir %>/bin/<%= @name %> eval "Freedive.Release.password_reset"