I want to share my dev notes and journey with you all, this is in the order I remember them so might edit this post to tidy up later on.
This is not a “what you should do” piece, I try to stay away from stating my opinion on tech, more of what worked for me, and my mental notes as well as my workarounds. There might be better ones out there that I don’t know about, I am a newbie to the whole ecosystem.
Ecto:
I haven’t done anything complex with ecto this time that grants a note but all the time I ran on production with multiple branches and different migrations in them. When I came back to my main
branch it was a relief to not have any DB migration conflicts on the actual DB since everything was done by timestamps on Ecto. Very pleased with that! Phew
Milligram CSS, bespoke CSS:
F that library.
Grab yourself some battle-tested and verified tools like bootstrap or Bulma likes, install NPM package, include into your scss
and you are done.
SVG icons:
I was using inline SVG definitions from heroicons and taking a hit on the payloads, nope, retire that too. Get yourself fontawesome either via CDN or npm package.
Webpack:
At this point you might realize your visual UI, changes are not reflected in the code whatever you do, restarts, refresh, clear cache.
This is webpack being a little B.
Grab yourself this plugin, problems go away!
plugins: [
new MiniCssExtractPlugin({ filename: '../css/app.css' }),
new CleanWebpackPlugin(),
new CopyWebpackPlugin([{ from: 'static/', to: '../' }])
]
Showing MIX_ENV and version in the UI:
Very useful for techy devs knowing what branch, env and version they are dealing with on the server.
For this, you need to configure your config/config.exs
Find your main app config, add another atom :env
config :ex,
ecto_repos: [Ex.Repo],
env: Mix.env()
Then your template you can do
<%= Application.get_env(:ex, :env) %>:<%= Application.spec(:ex, :vsn) %>
Getting some unusual traffic, no idea what is going on. No IP in logs:
Add a plug. I am behind nginx so I set x-forwarded-for myself in the nginx and search for that.
defmodule ExWeb.Plugs.ClientIp do
require Logger
@behaviour Plug
def init(opts), do: opts
def call(conn, _opts) do
Logger.metadata(client_ip: get_ip(conn))
conn
end
# This code is from Plausible Analytics https://github.com/plausible/analytics/blob/3a1c9e67cd67d5cb1fec68a4dee34f8cd0e056fd/lib/plausible_web/remote_ip.ex
def get_ip(conn) do
forwarded_for = List.first(Plug.Conn.get_req_header(conn, "x-forwarded-for"))
if forwarded_for do
String.split(forwarded_for, ",")
|> Enum.map(&String.trim/1)
|> List.first()
else
to_string(:inet_parse.ntoa(conn.remote_ip))
end
end
end
in your endpoint.ex
add the plug
plug ExWeb.Plugs.ClientIp
in your config.exs
configure your logger to record ip
# Configures Elixir's Logger*
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id, :client_ip]
That is definitely some dodgy BOT traffic:
Visit old friend https://www.abuseipdb.com/ community to log in to my account, report IPs, and batch download top 10K to block
Too many IPs to manage via Iptables:
Use ipset! https://confluence.jaytaala.com/display/TKB/Using+ipset+to+block+IP+addresses+-+firewall
Bots now get on the forms to spam, don’t want google snooping on users:
Come up with “finger”
Publish as a library, first elixir package and some new learning finger | Hex
Taking it a bit further Finger, a verification library to prove hommaannnnnness of a user - #17 by cenotaph
What is this 5 lines of phoenix vsn code in the logs?
Returns true if the socket is connected and the tracked static assets have changed. This function is useful to detect if the client is running on an outdated version of the marked static files. It works by comparing the static paths sent by the client with the one on the server.
My releases don’t work that way and don’t have live dependency stuff now. remove all the track-static
from template.
I have tabs for budget and job hunt now. I want to select active items and set the necessary tabs when they are needed only.
Make a tab plug
defmodule ExWeb.Plugs.Tab do
import Plug.Conn
def init(default), do: default
def call(conn, default) do
assign(conn |> put_session(:ex_tabs, default), :ex_tabs, default)
end
end
create a derived pipeline
pipeline :jobhunt do
plug :board
plug ExWeb.Plugs.Tab, "_jobhunt_tabs.html"
end
scope it so all the sub-resources get the tabs
# job-hunt scope
scope "/job-hunt/stuff", ExWeb do
pipe_through :jobhunt
template rendering
<%= if assigns[:ex_tabs] do %>
<%= render assigns.ex_tabs, assigns %>
<% end %>
Select active items in the menu and tabs based on url:
add to view helpers
def is_active?(%Plug.Conn{} = conn, section) when is_list(section) do
if Enum.all?(section, &Enum.member?(conn.path_info, &1)), do: "is-active", else: ""
end
def is_active?(%Plug.Conn{} = conn, section) when is_binary(section) do
if section in conn.path_info, do: "is-active", else: ""
end
JS Date pickers do not work with liveview:
Try a workaround, post in forums, to investigate further Correct strategy for using datepicker attached to an input field with Liveview? - #11 by cenotaph
Fail2ban is great with abuseipdb:
But uses too much memory on my vps and will have to write custom jails for stuff. some manual labor will have to do for now.
Useful journal commands to spot issues and ban bots:
// Show all the activity since 8 hours who had 404 results and take 1 request before it. Usually, bots trying to poke holes
journalctl -u elxsy --since "8 hours ago" | grep "404" -B1
// Make shift mass banner since these are all dodgy urls no one should be visiting or posting to Wordpress, cancer of the internet!
journalctl -u elxsy --since "1 days ago" |
grep -E "wp-login|xmlrpc|wp-includes|actuator\/health|.env|logon.aspx" |
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' |
while read -r ip ; do
if [[ ! `ipset test blacklist $ip` ]] &>/dev/null; then
echo -e "Added\t$ip"
ipset add blacklist $ip &>/dev/null
#else
# echo -e "Skipped\t$ip"
fi
done