James_E
I’m developing an application that’s going to be (for the forseeable future) installed and managed in a pretty boring, standard way — not using bespoke containerization, clustering, or anything like that.
I’ve currently got this code to manage SECRET_KEY_BASE, and it seems to work, but it also seems like a really messy hack:
# /config/runtime.exs
# …
if config_env() == :prod do
# …
secret_key_base =
System.get_env("SECRET_KEY_BASE")
|| Foo.Application.Util.app_secret_key_auto()
# …
end
# /lib/foo/util.ex
defmodule Foo.Application.Util do
# …
def app_secret_key_auto do
p = Path.expand("secret_key_base.txt", :filename.basedir(:user_config, "foo-app"))
# 1. Generate key if it doesn't exist
:ok = mkdir_p(Path.expand("..", p))
:ok = case File.open(p, [:write, :exclusive]) do # FIXME surely there must be some built-in tooling for this???
{:error, :eexist} -> :ok # happy path
{:ok, h} ->
case File.chmod(p, 0o600) do
:ok ->
# https://github.com/phoenixframework/phoenix/blob/v1.7.17/lib/mix/tasks/phx.gen.secret.ex#L17
data_ascii = (&:crypto.strong_rand_bytes(&1) |> Base.encode64(padding: false) |> binary_part(0, &1)).(64)
result = IO.write(h, data_ascii)
:ok = File.close(h)
result
{:error, e} ->
:ok = File.close(h)
{:error, e}
end
{:error, e} -> {:error, e}
end
# 2. load key
{:ok, data_ascii} = File.open(p, [:read], &Enum.fetch!(IO.stream(&1, :line), 0))
data_ascii
end
end
Is there any existing utility function or simple pattern that I should be using instead of this pile of spaghetti, or is Phoenix really just not meant to be used outside of cloud containers?
The documentation didn’t say much about it.
Trending in Questions
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
Hello,
I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind.
However, when I launch mix phx.server, I get an error...
New
Hi everyone,
I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding.
I sta...
New
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
I’m working on a small exercise involving update_in/3, and I came up with this solution:
data = %{
name: "Periodic Table",
category:...
New
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication):
toke...
New
Other Trending Topics
Edit: 2026 May 15 - This post is archived.
Mob is alive!!
Main docs: mob v0.7.11 — Documentation
A bit of explanation for the slightly c...
New
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
A little off-topic, but I feel like people here have a good head on their shoulders.
I used to be quite good at making software. Was luc...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ai
- #ecto-query
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #metaprogramming
- #hex











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
axelson
Hmm, generally I wouldn’t generate the
SECRET_KEY_BASEif it doesn’t exist, I’d instead always pass it in via Env variables. Specifically these are the situations I’ve dealt with before that didn’t involve Kubernetes/Docker:EnvironmentFile=/path/to/some/.envfileThat way the only snippet you need is something like:
LostKobrakai
Adding one more option:
env $(cat .env | xargs) ./bin/app remoteIn the end system env is the complete opposite than catered to the cloud. You can provide those in a million ways and there’s likely one fitting your workflow – and it’s completely independent from the fact that you’re running elixir at all.
linusdm
Just as a side note: there is a mix task to create a secret key.
James_E
The snippet you posted is actually the stock behavior of the
phx.newtemplate; I edited it away from that because I don’t want my server to crash on startup just because the technician attempted a perfectly reasonable ZIP installation.The app isn’t being deployed in any kind of fancy cloud service, either. Heck, right now it’s targeting Windows server (though we hope to move over to Linux at some point.)
I guess that I could bundle extra instructions with the application demanding that the installing technician fiddle with the registry to get basic functionality… but is there really not any established pattern for making Phoenix “just work” in the absence of a fancy managed environment? (And even on Linux, putting a systemd service that references an external file just passes the buck of generating that file…)
That task seems to be hard-coded to send the result to standard output. I actually linked to that line in the comment at the top the bit of my code that does what that task would.
James_E
Or maybe I’m X-Y problemming this.
What, specifically, would go wrong if I simply set
:secret_key_baserandomly on startup whenever the environment doesn’t specify it? Would everything work perfectly so long as the app isn’t being clustered/distributed/whatever, or would I be laying the seeds of—for example—a catastrophic Ecto failure next time the server restarts?If the former, it seems like it would be pretty simple to raise if and only if it’s unspecified and the app is being run in a way that actually requires a non-arbitrary value for it… am I missing something?
LostKobrakai
Sessions are signed with the secret key. So all session cookies of user will become invalid, effectively logging them out if the were logged in and dropping any other stuff you might have stored in the session. Similarly csrf token given out (e.g. as part of forms) will become invalid, so users still having a form open won’t be able to successfully submit their forms.
Phoenix.Tokens also reply on the secret if you happen to use those.James_E
I see… so if I just randomize it on startup, then users authenticated based on session cookies will be logged out, any CSRF-protected flows will be interrupted, and any
Phoenix.tokens will be ungracefully invalidated. Definitely not great.Since keeping it stable is apparently so crucial to so much of Phoenix’s operation, what are the risks/drawbacks to just storing it in Ecto after automatically generating it on the first run?
LostKobrakai
I’m wondering if you’re not better off figuring out system env on windows over figuring out how to work around it. Releases support being installed as windows services, which based on the docs allow you to define additional system env values.
erlsrv — OTP 29.0.2 (erts 17.0.2) (See Env parameter)
James_E
Hmm, one difficulty I’m running into there is that Ecto isn’t started during config-load time:
Is there any best practice for making parts of Endpoint config depend on values stored in Ecto, like that? If I were to start Ecto within this file, I’m pretty sure that’d break the supervisor structure, and I don’t see any obvious clean way to transform the
phx.newtemplate to do that. Maybe a separate:ignoreprocess that runs immediately afterEcto.Migrator?benwilson512
This seems like a LOT of hoops to jump through just to avoid the actual good practice of doing a rolling deploy. And if you can’t rely on an environment variable being present on boot, how are you going to connect to the database anyway? Is that not also configured via an env var?
Zooming out: your app has preconditions to booting. The correct thing to do when those preconditions are not met is to not boot, which allows the currently running instance to continue to serve traffic. The boot failure goes to your logs, which gives you alerts, and you fix it.
None of that is docker or container specific, that’s been the normal rolling deploy pattern for 20+ years now.