Override default API url in local/staging envs (#2611)

This commit is contained in:
Andrew Dryga
2023-11-09 11:41:38 -06:00
committed by GitHub
parent e89b5339f9
commit a7701c07de
13 changed files with 291 additions and 93 deletions

View File

@@ -606,10 +606,11 @@ defmodule Domain.Config.Definitions do
)
##############################################
## Docker Registry
## Local development and Staging Helpers
##############################################
defconfig(:docker_registry, :string, default: "ghcr.io/firezone")
defconfig(:api_url_override, :string, default: nil)
##############################################
## Feature Flags

View File

@@ -1,28 +1,10 @@
@layer utilities {
.no-scrollbar::-webkit-scrollbar {
display: block;
height: 0px;
background-color: initial;
border-radius: 10px;
transition: all 2s linear;
}
.no-scrollbar:hover::-webkit-scrollbar {
height: .5rem;
display: none;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
.no-scrollbar::-webkit-scrollbar-thumb {
background-color: rgb(228 228 231/var(--tw-bg-opacity));
border-radius: 10px;
}
.no-scrollbar::-webkit-scrollbar-track {
background-color: rgb(249 250 251);
border-radius: 5px;
}
}

View File

@@ -9,7 +9,10 @@ Hooks.Copy = {
this.el.addEventListener("click", (ev) => {
ev.preventDefault();
let text = ev.currentTarget.querySelector("[data-copy]").innerHTML.trim();
let inner_html = ev.currentTarget.querySelector("[data-copy]").innerHTML.trim();
let doc = new DOMParser().parseFromString(inner_html, "text/html");
let text = doc.documentElement.textContent;
let cl = ev.currentTarget.querySelector("[data-icon]").classList
navigator.clipboard.writeText(text).then(() => {

View File

@@ -102,10 +102,16 @@ defmodule Web.CoreComponents do
attr :label, :any, required: true, doc: "Display label for the tab"
end
attr :rest, :global
def tabs(assigns) do
~H"""
<div class="mb-4">
<div class="border-gray-200 dark:border-gray-700 bg-slate-50 rounded-t">
<div
class="border-gray-200 dark:border-gray-700 bg-slate-50 rounded-t"
id={"#{@id}-container"}
{@rest}
>
<ul
class="flex flex-wrap text-sm font-medium text-center"
id={"#{@id}-ul"}

View File

@@ -384,7 +384,7 @@ defmodule Web.FormComponents do
def add_button(assigns) do
~H"""
<.button style="primary" navigate={@navigate} icon="hero-plus">
<.button style="primary" class={@class} navigate={@navigate} icon="hero-plus">
<%= render_slot(@inner_block) %>
</.button>
"""

View File

@@ -43,16 +43,63 @@ defmodule Web.RelayGroups.New do
<div class="text-xl mb-2">
Select deployment method:
</div>
<.tabs id="deployment-instructions">
<.tabs id="deployment-instructions" phx-update="ignore">
<:tab id="docker-instructions" label="Docker">
<.code_block id="code-sample-docker" class="w-full rounded-b" phx-no-format><%= docker_command(encode_group_token(@group)) %></.code_block>
<p class="pl-4 mb-2">
Copy-paste this command to your server and replace <code>PUBLIC_IP4_ADDR</code>
and <code>PUBLIC_IP6_ADDR</code>
with your public IP addresses:
</p>
<.code_block id="code-sample-docker" class="w-full rounded-b" phx-no-format><%= docker_command(@env) %></.code_block>
</:tab>
<:tab id="systemd-instructions" label="Systemd">
<.code_block id="code-sample-systemd" class="w-full rounded-b" phx-no-format><%= systemd_command(encode_group_token(@group)) %></.code_block>
<p class="pl-4 mb-2">
1. Create a systemd unit file with the following content:
</p>
<.code_block id="code-sample-systemd" class="w-full" phx-no-format>sudo nano /etc/systemd/system/firezone-relay.service</.code_block>
<p class="pl-4 mb-2 mt-4">
2. Copy-paste the following content into the file and replace
<code>PUBLIC_IP4_ADDR</code>
and <code>PUBLIC_IP6_ADDR</code>
with your public IP addresses::
</p>
<.code_block id="code-sample-systemd" class="w-full rounded-b" phx-no-format><%= systemd_command(@env) %></.code_block>
<p class="pl-4 mb-2 mt-4">
3. Save by pressing <kbd>Ctrl</kbd>+<kbd>X</kbd>, then <kbd>Y</kbd>, then <kbd>Enter</kbd>.
</p>
<p class="pl-4 mb-2 mt-4">
4. Reload systemd configuration:
</p>
<.code_block id="code-sample-systemd" class="w-full" phx-no-format>sudo systemctl daemon-reload</.code_block>
<p class="pl-4 mb-2 mt-4">
5. Start the service:
</p>
<.code_block id="code-sample-systemd" class="w-full" phx-no-format>sudo systemctl start firezone-relay</.code_block>
<p class="pl-4 mb-2 mt-4">
6. Enable the service to start on boot:
</p>
<.code_block id="code-sample-systemd" class="w-full" phx-no-format>sudo systemctl enable firezone-relay</.code_block>
<p class="pl-4 mb-2 mt-4">
7. Check the status of the service:
</p>
<.code_block id="code-sample-systemd" class="w-full rounded-b" phx-no-format>sudo systemctl status firezone-relay</.code_block>
</:tab>
</.tabs>
<div class="mt-4 animate-pulse">
<div class="mt-4 animate-pulse text-center">
Waiting for relay connection...
</div>
</div>
@@ -76,7 +123,8 @@ defmodule Web.RelayGroups.New do
with {:ok, group} <-
Relays.create_group(attrs, socket.assigns.subject) do
:ok = Relays.subscribe_for_relays_presence_in_group(group)
{:noreply, assign(socket, group: group)}
token = encode_group_token(group)
{:noreply, assign(socket, group: group, env: env(token))}
else
{:error, changeset} ->
{:noreply, assign(socket, form: to_form(changeset))}
@@ -92,30 +140,99 @@ defmodule Web.RelayGroups.New do
{:noreply, socket}
end
defp docker_command(secret) do
"""
docker run -d \\
--name=firezone-relay-0 \\
--restart=always \\
-v /dev/net/tun:/dev/net/tun \\
-e FIREZONE_TOKEN=#{secret} \\
us-east1-docker.pkg.dev/firezone/firezone/relay:stable
"""
defp version do
vsn =
Application.spec(:domain)
|> Keyword.fetch!(:vsn)
|> List.to_string()
|> Version.parse!()
"#{vsn.major}.#{vsn.minor}"
end
defp systemd_command(_secret) do
"""
[Unit]
Description=zigbee2mqtt
After=network.target
defp env(token) do
api_url_override =
if api_url = Domain.Config.get_env(:web, :api_url_override) do
{"FIREZONE_API_URL", api_url}
end
[Service]
ExecStart=/usr/bin/npm start
WorkingDirectory=/opt/zigbee2mqtt
StandardOutput=inherit
StandardError=inherit
Restart=always
User=pi
[
{"FIREZONE_ID", Ecto.UUID.generate()},
{"FIREZONE_TOKEN", token},
{"PUBLIC_IP4_ADDR", "YOU_MUST_SET_THIS_VALUE"},
{"PUBLIC_IP6_ADDR", "YOU_MUST_SET_THIS_VALUE"},
api_url_override,
{"RUST_LOG", "warn"},
{"LOG_FORMAT", "google-cloud"}
]
|> Enum.reject(&is_nil/1)
end
defp docker_command(env) do
[
"docker run -d",
"--restart=unless-stopped",
"--pull=always",
"--health-cmd=\"lsof -i UDP | grep firezone-relay\"",
"--name=firezone-relay",
"--cap-add=NET_ADMIN",
"--sysctl net.ipv4.ip_forward=1",
"--sysctl net.ipv4.conf.all.src_valid_mark=1",
"--sysctl net.ipv6.conf.all.disable_ipv6=0",
"--sysctl net.ipv6.conf.all.forwarding=1",
"--sysctl net.ipv6.conf.default.forwarding=1",
"--device=\"/dev/net/tun:/dev/net/tun\"",
Enum.map(env, fn {key, value} -> "--env #{key}=\"#{value}\"" end),
"--env FIREZONE_HOSTNAME=$(hostname)",
"#{Domain.Config.fetch_env!(:domain, :docker_registry)}/relay:#{version()}"
]
|> List.flatten()
|> Enum.join(" \\\n ")
end
defp systemd_command(env) do
"""
[Unit]
Description=Firezone Relay
After=network.target
[Service]
Type=simple
#{Enum.map_join(env, "\n", fn {key, value} -> "Environment=\"#{key}=#{value}\"" end)}
ExecStartPre=/bin/sh -c ' \\
remote_version=$(curl -Ls \\
-H "Accept: application/vnd.github+json" \\
-H "X-GitHub-Api-Version: 2022-11-28" \\
https://api.github.com/repos/firezone/firezone/releases/latest | grep -oP '"'"'(?<="tag_name": ")[^"]*'"'"'); \\
if [ -e /usr/local/bin/firezone-relay ]; then \\
current_version=$(/usr/local/bin/firezone-relay --version | awk '"'"'{print $NF}'"'"'); \\
else \\
current_version=""; \\
fi; \\
if [ ! "$current_version" = "$remote_version" ]; then \\
arch=$(uname -m); \\
case $arch in \\
aarch64) \\
bin_url="https://github.com/firezone/firezone/releases/download/latest/relay-arm64" ;; \\
armv7l) \\
bin_url="https://github.com/firezone/firezone/releases/download/latest/relay-arm" ;; \\
x86_64) \\
bin_url="https://github.com/firezone/firezone/releases/download/latest/relay-x64" ;; \\
*) \\
echo "Unsupported architecture"; \\
exit 1 ;; \\
esac; \\
wget -O /usr/local/bin/firezone-relay $bin_url; \\
chmod +x /usr/local/bin/firezone-relay; \\
fi \\
'
ExecStartPre=/usr/bin/chmod +x /usr/local/bin/firezone-relay
ExecStart=FIREZONE_HOSTNAME=$(hostname) /usr/local/bin/firezone-relay
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
"""
end

View File

@@ -4,12 +4,20 @@ defmodule Web.Sites.NewToken do
def mount(%{"id" => id}, _session, socket) do
with {:ok, group} <- Gateways.fetch_group_by_id(id, socket.assigns.subject) do
{:ok, group} =
Gateways.update_group(%{group | tokens: []}, %{tokens: [%{}]}, socket.assigns.subject)
{group, env} =
if connected?(socket) do
{:ok, group} =
Gateways.update_group(%{group | tokens: []}, %{tokens: [%{}]}, socket.assigns.subject)
:ok = Gateways.subscribe_for_gateways_presence_in_group(group)
:ok = Gateways.subscribe_for_gateways_presence_in_group(group)
{:ok, assign(socket, group: group)}
token = encode_group_token(group)
{group, env(token)}
else
{group, nil}
end
{:ok, assign(socket, group: group, env: env)}
else
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
end
@@ -37,16 +45,58 @@ defmodule Web.Sites.NewToken do
<div class="text-xl mb-2">
Select deployment method:
</div>
<.tabs id="deployment-instructions">
<.tabs :if={@env} id="deployment-instructions" phx-update="ignore">
<:tab id="docker-instructions" label="Docker">
<.code_block id="code-sample-docker" class="w-full rounded-b" phx-no-format><%= docker_command(encode_group_token(@group)) %></.code_block>
<p class="pl-4 mb-2">
Copy-paste this command to your server:
</p>
<.code_block id="code-sample-docker" class="w-full rounded-b" phx-no-format><%= docker_command(@env) %></.code_block>
</:tab>
<:tab id="systemd-instructions" label="Systemd">
<.code_block id="code-sample-systemd" class="w-full rounded-b" phx-no-format><%= systemd_command(encode_group_token(@group)) %></.code_block>
<p class="pl-4 mb-2">
1. Create a systemd unit file with the following content:
</p>
<.code_block id="code-sample-systemd" class="w-full" phx-no-format>sudo nano /etc/systemd/system/firezone-gateway.service</.code_block>
<p class="pl-4 mb-2 mt-4">
2. Copy-paste the following content into the file:
</p>
<.code_block id="code-sample-systemd" class="w-full rounded-b" phx-no-format><%= systemd_command(@env) %></.code_block>
<p class="pl-4 mb-2 mt-4">
3. Save by pressing <kbd>Ctrl</kbd>+<kbd>X</kbd>, then <kbd>Y</kbd>, then <kbd>Enter</kbd>.
</p>
<p class="pl-4 mb-2 mt-4">
4. Reload systemd configuration:
</p>
<.code_block id="code-sample-systemd" class="w-full" phx-no-format>sudo systemctl daemon-reload</.code_block>
<p class="pl-4 mb-2 mt-4">
5. Start the service:
</p>
<.code_block id="code-sample-systemd" class="w-full" phx-no-format>sudo systemctl start firezone-gateway</.code_block>
<p class="pl-4 mb-2 mt-4">
6. Enable the service to start on boot:
</p>
<.code_block id="code-sample-systemd" class="w-full" phx-no-format>sudo systemctl enable firezone-gateway</.code_block>
<p class="pl-4 mb-2 mt-4">
7. Check the status of the service:
</p>
<.code_block id="code-sample-systemd" class="w-full rounded-b" phx-no-format>sudo systemctl status firezone-gateway</.code_block>
</:tab>
</.tabs>
<div class="mt-4 animate-pulse">
<div :if={@env} class="mt-4 animate-pulse text-center">
Waiting for gateway connection...
</div>
</div>
@@ -65,30 +115,45 @@ defmodule Web.Sites.NewToken do
"#{vsn.major}.#{vsn.minor}"
end
defp docker_command(token) do
"""
docker run -d \\
--restart=unless-stopped \\
--pull=always \\
--health-cmd="ip link | grep tun-firezone" \\
--name=firezone-gateway \\
--cap-add=NET_ADMIN \\
--sysctl net.ipv4.ip_forward=1 \\
--sysctl net.ipv4.conf.all.src_valid_mark=1 \\
--sysctl net.ipv6.conf.all.disable_ipv6=0 \\
--sysctl net.ipv6.conf.all.forwarding=1 \\
--sysctl net.ipv6.conf.default.forwarding=1 \\
--device="/dev/net/tun:/dev/net/tun" \\
--env FIREZONE_ID="#{Ecto.UUID.generate()}" \\
--env FIREZONE_TOKEN="#{token}" \\
--env FIREZONE_ENABLE_MASQUERADE=1 \\
--env FIREZONE_HOSTNAME="`hostname`" \\
--env RUST_LOG="warn" \\
#{Domain.Config.fetch_env!(:domain, :docker_registry)}/gateway:#{version()}
"""
defp env(token) do
api_url_override =
if api_url = Domain.Config.get_env(:web, :api_url_override) do
{"FIREZONE_API_URL", api_url}
end
[
{"FIREZONE_ID", Ecto.UUID.generate()},
{"FIREZONE_TOKEN", token},
{"FIREZONE_ENABLE_MASQUERADE", "1"},
api_url_override,
{"RUST_LOG", "warn"}
]
|> Enum.reject(&is_nil/1)
end
defp systemd_command(token) do
defp docker_command(env) do
[
"docker run -d",
"--restart=unless-stopped",
"--pull=always",
"--health-cmd=\"ip link | grep tun-firezone\"",
"--name=firezone-gateway",
"--cap-add=NET_ADMIN",
"--sysctl net.ipv4.ip_forward=1",
"--sysctl net.ipv4.conf.all.src_valid_mark=1",
"--sysctl net.ipv6.conf.all.disable_ipv6=0",
"--sysctl net.ipv6.conf.all.forwarding=1",
"--sysctl net.ipv6.conf.default.forwarding=1",
"--device=\"/dev/net/tun:/dev/net/tun\"",
Enum.map(env, fn {key, value} -> "--env #{key}=\"#{value}\"" end),
"--env FIREZONE_HOSTNAME=$(hostname)",
"#{Domain.Config.fetch_env!(:domain, :docker_registry)}/gateway:#{version()}"
]
|> List.flatten()
|> Enum.join(" \\\n ")
end
defp systemd_command(env) do
"""
[Unit]
Description=Firezone Gateway
@@ -96,34 +161,36 @@ defmodule Web.Sites.NewToken do
[Service]
Type=simple
Environment="FIREZONE_TOKEN=#{token}"
Environment="FIREZONE_VERSION=#{version()}"
Environment="FIREZONE_HOSTNAME=$(hostname)"
Environment="FIREZONE_ENABLE_MASQUERADE=1"
#{Enum.map_join(env, "\n", fn {key, value} -> "Environment=\"#{key}=#{value}\"" end)}
ExecStartPre=/bin/sh -c ' \\
remote_version=$(curl -Ls \\
-H "Accept: application/vnd.github+json" \\
-H "X-GitHub-Api-Version: 2022-11-28" \\
https://api.github.com/repos/firezone/firezone/releases/latest | grep -oP '"'"'(?<="tag_name": ")[^"]*'"'"'); \\
if [ -e /usr/local/bin/firezone-gateway ]; then \\
current_version=$(/usr/local/bin/firezone-gateway --version 2>&1 | awk "{print $NF}"); \\
current_version=$(/usr/local/bin/firezone-gateway --version | awk '"'"'{print $NF}'"'"'); \\
else \\
current_version=""; \\
fi; \\
if [ ! "$$current_version" = "${FIREZONE_VERSION}" ]; then \\
if [ ! "$current_version" = "$remote_version" ]; then \\
arch=$(uname -m); \\
case $$arch in \\
case $arch in \\
aarch64) \\
bin_url="https://github.com/firezone/firezone/releases/download/${FIREZONE_VERSION}/gateway-aarch64-unknown-linux-musl-${FIREZONE_VERSION}" ;; \\
bin_url="https://github.com/firezone/firezone/releases/download/latest/gateway-arm64" ;; \\
armv7l) \\
bin_url="https://github.com/firezone/firezone/releases/download/${FIREZONE_VERSION}/gateway-armv7-unknown-linux-musleabihf-${FIREZONE_VERSION}" ;; \\
bin_url="https://github.com/firezone/firezone/releases/download/latest/gateway-arm" ;; \\
x86_64) \\
bin_url="https://github.com/firezone/firezone/releases/download/${FIREZONE_VERSION}/gateway-x86_64-unknown-linux-musl-${FIREZONE_VERSION}" ;; \\
bin_url="https://github.com/firezone/firezone/releases/download/latest/gateway-x64" ;; \\
*) \\
echo "Unsupported architecture"; \\
exit 1 ;; \\
esac; \\
wget -O /usr/local/bin/firezone-gateway $$bin_url; \\
wget -O /usr/local/bin/firezone-gateway $bin_url; \\
chmod +x /usr/local/bin/firezone-gateway; \\
fi \\
'
ExecStartPre=/usr/bin/chmod +x /usr/local/bin/firezone-gateway
ExecStart=/usr/local/bin/firezone-gateway
ExecStart=FIREZONE_HOSTNAME=$(hostname) /usr/local/bin/firezone-gateway
Restart=always
RestartSec=3

View File

@@ -123,7 +123,7 @@ defmodule Web.Live.RelayGroups.NewTest do
assert html =~ "docker run"
assert html =~ "Waiting for relay connection..."
token = Regex.run(~r/FIREZONE_TOKEN=([^ ]+)/, html) |> List.last()
token = Regex.run(~r/FIREZONE_TOKEN=&quot;([^ ]+)&quot;/, html) |> List.last()
assert {:ok, _token} = Domain.Relays.authorize_relay(token)
group = Repo.get_by(Domain.Relays.Group, name: attrs.name) |> Repo.preload(:tokens)

View File

@@ -130,6 +130,8 @@ config :web, Web.Plugs.SecureHeaders,
"connect-src 'self' https://firezone.statuspage.io"
]
config :web, api_url_override: "ws://localhost:13001/"
###############################
##### API #####################
###############################

View File

@@ -64,6 +64,10 @@ config :web, Web.Plugs.SecureHeaders,
"connect-src 'self' data: https://firezone.statuspage.io"
]
# Note: on Linux you may need to add `--add-host=host.docker.internal:host-gateway`
# to the `docker run` command. Works on Docker v20.10 and above.
config :web, api_url_override: "ws://host.docker.internal:13001/"
###############################
##### API #####################
###############################

View File

@@ -107,6 +107,8 @@ if config_env() == :prod do
cookie_signing_salt: compile_config!(:cookie_signing_salt),
cookie_encryption_salt: compile_config!(:cookie_encryption_salt)
config :web, api_url_override: compile_config!(:api_url_override)
###############################
##### API #####################
###############################

View File

@@ -14,6 +14,12 @@ resource "random_password" "metabase_db_password" {
min_special = 1
}
# This user can also be used to connect to the Firezone database,
# but following SQL should be run manually using the Cloud SQL Proxy:
#
# GRANT SELECT ON ALL TABLES IN SCHEMA public TO metabase;
# GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO metabase;
#
resource "google_sql_user" "metabase" {
project = module.google-cloud-project.project.project_id
@@ -85,6 +91,10 @@ module "metabase" {
name = "MB_ANON_TRACKING_ENABLED"
value = "false"
},
# {
# name = "MB_JETTY_PORT"
# value = "80"
# }
]
health_check = {

View File

@@ -485,7 +485,11 @@ module "web" {
{
name = "PHOENIX_HTTP_WEB_PORT"
value = "8080"
}
},
{
name = "API_URL_OVERRIDE"
value = "wss://api.${local.tld}"
},
], local.shared_application_environment_variables)
application_labels = {