-
-
Notifications
You must be signed in to change notification settings - Fork 112
feat: dockerize initial #522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Just a heads-up, |
|
Making sure of that, thanks 👍 I'll be finishing up the MR presumably by the end of the weekend. |
2b62cdc to
a33ef8a
Compare
Signed-off-by: Elvio Petillo <elvio.petillo@nanowaris.com>
Signed-off-by: Elvio Petillo <elvio.petillo@nanowaris.com>
2bab8e2 to
2ee99bf
Compare
|
Before handing over the PR for review, there are still a few things left to do:
|
Signed-off-by: Elvio Petillo <elvio.petillo@nanowaris.com>
5b559e6 to
bae96e7
Compare
Signed-off-by: Elvio Petillo <elvio.petillo@nanowaris.com>
8551e27 to
5d66664
Compare
Signed-off-by: Elvio Petillo <elvio.petillo@nanowaris.com>
Signed-off-by: Elvio Petillo <elvio.petillo@nanowaris.com>
|
A couple more comments from my side:
|
|
@Flash1232 From my testing and from documentation this docker image is going to have pre-baked environment variables (VITE_* prefix), meaning that it would work fine for a static url that is known during development (i.e stoat.chat) but in a self-hosted environment it wouldn't really be useful since it needs to be able to change. DEFAULT_WS_URL:
(import.meta.env.DEV ? import.meta.env.VITE_DEV_WS_URL : undefined) ??
(import.meta.env.VITE_WS_URL as string) ??
"wss://stoat.chat/events",And from vite documentation:
If instead of starting nginx instantly after we copy the files, we can execute a script to append the env variables to the index.html. #!/bin/sh
set -e
build_env_js() {
local env_vars="{"
local first=true
# Get all environment variables that start with VITE_
for var in $(env | grep '^VITE_' | cut -d'=' -f1); do
local value="${!var}"
if [ "$first" = true ]; then
first=false
else
env_vars="${env_vars}, "
fi
env_vars="${env_vars}\"$var\": \"$value\""
done
env_vars="${env_vars}}"
# Build the javascript object
echo "<script>window.__ENV__ = ${env_vars};</script>"
}
ENV_JS=$(build_env_js)
echo "Injecting runtime environment variables into HTML file..."
html_file="/usr/share/nginx/html/index.html"
if [ -f "$html_file" ]; then
sed -i 's|</head>|'"${ENV_JS}"'\n</head>|g' "$html_file"
fi
echo "Starting nginx..."
exec nginx -g 'daemon off;'then we can access these environment variables by parsing them at runtime: declare global {
interface Window {
__ENV__?: Record<string, string>;
}
}
const runtimeEnv =
typeof window !== "undefined" && window.__ENV__ ? window.__ENV__ : {};
/**
* Safely retrieves an environment variable, handling both build-time (import.meta.env)
* and runtime (window.__ENV__) environments with proper fallbacks.
*/
function getEnvVar(key: string, fallback?: string): string {
// In development, check import.meta.env first
if (import.meta.env.DEV) {
const value = import.meta.env[key];
if (value && typeof value === "string" && value.trim()) {
return value.trim();
}
}
// Check runtime environment
const runtimeValue = runtimeEnv[key];
if (runtimeValue && typeof runtimeValue === "string" && runtimeValue.trim()) {
return runtimeValue.trim();
}
// Return fallback or empty string
return fallback || "";
}
/**
* Safely retrieves an environment variable with dev-specific override support.
* Checks VITE_DEV_{KEY} first in dev mode, then falls back to VITE_{KEY}.
*/
function getEnvVarWithDevOverride(key: string, fallback: string): string {
if (import.meta.env.DEV) {
// Try dev-specific override first
const devValue = getEnvVar(`VITE_DEV_${key}`);
if (devValue) return devValue;
// Fall back to regular key
const regularValue = getEnvVar(`VITE_${key}`);
if (regularValue) return regularValue;
}
// In production, use runtime env
return getEnvVar(`VITE_${key}`, fallback);
}
/**
* Safely retrieves an optional environment variable that may not exist.
*/
function getOptionalEnvVar(key: string): string | undefined {
const value = getEnvVar(key);
return value || undefined;
}
const DEFAULT_API_URL = getEnvVarWithDevOverride(
"API_URL",
"https://stoat.chat/api",
);I don't know if this would be a good pattern, or something that may not want to be implemented, just thought to let you know since I had to handle this to deploy the new for-web client, and to let you know. |
Thanks for bringing this up, I've observed this now as well when testing with the updated self-hosted part.
For me, the problem we're facing is indeed a bit tricky if we want to solve it preserving some best-practices with Docker:
I am reluctant to just sacrifice security for this. So I was inspired by a different idea: As we already have an nginx inside the very same client service, we can just let it pass the env vars via SSI to the frontend. This lets us keep "read_only=true" as well as makes it possible to change the URLs at runtime. I will expand on this later on, but TLDR; We can create tmpfs for nginx and provide it with "template configs": These can contain I would deem it semi-elegant as it requires us to set |
|
That's a great idea, you are right that having the script do the modifications is a security risk, great catch about using SSI since it practically solves the issue, regarding having to set |
As discussed in stoatchat/self-hosted#176
TODOs:
compose.ymlin self-hosted repo (chore: Add new for-web docker image self-hosted#177)would be cool ™️ (maybe in follow-up PR):