-
Notifications
You must be signed in to change notification settings - Fork 6k
Add comprehensive login page customization options #7374
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
Add CLI arguments and environment variables to customize all login page elements: - Login title, subtitle, and welcome text - Password field placeholder and submit button text - Password instruction messages (config file, env var, hashed) - Error messages (rate limit, missing/incorrect password) New CLI options: --login-title, --login-below, --password-placeholder, --submit-text --login-password-msg, --login-env-password-msg, --login-hashed-password-msg --login-rate-limit-msg, --missing-password-msg, --incorrect-password-msg New environment variables: CS_LOGIN_TITLE, CS_LOGIN_BELOW, CS_PASSWORD_PLACEHOLDER, CS_SUBMIT_TEXT CS_LOGIN_PASSWORD_MSG, CS_LOGIN_ENV_PASSWORD_MSG, CS_LOGIN_HASHED_PASSWORD_MSG CS_LOGIN_RATE_LIMIT_MSG, CS_MISSING_PASSWORD_MSG, CS_INCORRECT_PASSWORD_MSG Features: - Full backwards compatibility with existing --app-name/--welcome-text - HTML escaping for security (prevents XSS) - Config file support (YAML) - Priority: CLI args > env vars > config file > defaults - Internationalization preserved for non-customized messages Perfect for Docker deployments and corporate branding. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Thank you for the contribution! Thinking out loud, my first impression is that the flags are not scaling well. Since we have this concept of language files that we can use for strings in the app, I wonder if we can re-use this for user-provided strings as well? Maybe we have a flag that accepts a Then, all strings, including future ones, will automatically be available for configuration. What do you think? We could then also deprecate |
Sounds good. I'll work on that change. |
Replace non-scalable individual flags (--login-title, --login-below, etc.) with a unified --custom-strings flag that accepts JSON file paths or inline JSON for UI customization. This leverages the existing i18n system for better scalability and maintainability. Changes: - Add --custom-strings flag with JSON validation - Extend i18n system to merge custom strings with defaults - Remove newly-added individual login/UI flags - Deprecate legacy --app-name and --welcome-text flags - Update login route to use unified i18n system - Add comprehensive tests for new functionality - Update documentation with migration guide and examples 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Remove migration examples for flags that were never released. Only --app-name and --welcome-text were in the original codebase and might be used by existing users. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Replace outdated CS_* environment variable examples with the new --custom-strings flag approach. Include both inline JSON and mounted file examples for Docker users. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
@code-asher is this in line with what you were thinking? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this is exactly along the line I was thinking! Thank you, this is really great.
### Login page customization | ||
|
||
You can customize the login page using the `--custom-strings` flag: | ||
|
||
```bash | ||
code-server --custom-strings '{"LOGIN_TITLE": "My Code Server", "WELCOME": "Welcome to my portal"}' | ||
``` | ||
|
||
Or use a JSON file: | ||
```bash | ||
code-server --custom-strings /path/to/custom-strings.json | ||
``` | ||
|
||
Legacy individual flags (`--app-name`, `--welcome-text`) are still supported but deprecated. | ||
|
||
For detailed customization options and examples, see the [customization guide](./customization.md). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this flag is too niche to earn a callout in the FAQ, so we should delete this.
You can also customize the login page appearance - see our [customization guide](./customization.md). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am thinking we append an entry to guide.md
instead of the main readme. Something like:
## Internationalization and customization
You can customize some of code-server's strings for either internationalization or customization purposes. See our [customization guide](./customization.md).
@@ -0,0 +1,170 @@ | |||
# Login Page Customization |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about making this more generic rather than login-specific? I also think there is a fair bit of repetition here we could consolidate and I worry that this will get out of sync with the language file. We can also keep the legacy flags around, no need to say we might remove them eventually.
I also think it would be reasonable to keep this text in guide.md
rather than linking out to a new file. We have so many markdown files sometimes I get lost. 😅
Maybe something like:
Internationalization and customization
code-server allows you to provide a language file or JSON to configure certain strings. This can be used for both internationalization and customization.
For example:
code-server --i18n /custom-strings.json
code-server --i18n `{"WELCOME": "{{app}} ログイン"}`
Or this can be done in the config file:
i18n: |
{
"WELCOME": "Welcome to the {{app}} Development Portal",
}
You can combine this with the --locale
flag to configure language support for both code-server and VS Code in cases where code-server has no support but VS Code does. If you are using this for internationalization, please consider sending us a pull request to contribute it to i18n/locales
.
Available keys and placeholders
Refer to ../src/node/i18n/locales/en.json for a full list of the available keys for translations. Note that the only placeholders supported for each key are the ones used in the default string.
The --app-name
flag controls the {{app}}
placeholder in templates. If you want to change the name, you can either:
- Set
--app-name
(potentially alongside--i18n
) - Use
--i18n
and hardcode the name in your strings
Legacy flag
The --welcome-text
flag is now deprecated. Use the WELCOME
key instead.
@@ -287,6 +287,34 @@ docker run -it --name code-server -p 127.0.0.1:8080:8080 \ | |||
codercom/code-server:latest | |||
``` | |||
|
|||
### Customizing the login page |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This guide is just for installing code-server, I think we should omit this. Also the customization can be applied to any install method, not just Docker, so we would want to generalize it anyway.
@@ -93,6 +93,7 @@ export interface UserProvidedArgs extends UserProvidedCodeArgs { | |||
"app-name"?: string | |||
"welcome-text"?: string | |||
"abs-proxy-base-path"?: string | |||
"custom-strings"?: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about calling it i18n
?
export async function loadCustomStrings(customStringsArg?: string): Promise<void> { | ||
if (!customStringsArg) { | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already check the arg before passing it in, so we can make this non-optional.
export async function loadCustomStrings(customStringsArg?: string): Promise<void> { | |
if (!customStringsArg) { | |
return | |
} | |
export async function loadCustomStrings(customStringsArg: string): Promise<void> { |
if (args["custom-strings"]) { | ||
try { | ||
await loadCustomStrings(args["custom-strings"]) | ||
logger.info("Loaded custom strings") | ||
} catch (error) { | ||
logger.error("Failed to load custom strings", field("error", error)) | ||
throw error | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already add Failed to load custom strings
to the error, and any errors thrown here will already be logged (I think?), so I am thinking we remove the catch to avoid logging the error twice.
if (args["custom-strings"]) { | |
try { | |
await loadCustomStrings(args["custom-strings"]) | |
logger.info("Loaded custom strings") | |
} catch (error) { | |
logger.error("Failed to load custom strings", field("error", error)) | |
throw error | |
} | |
} | |
if (args["custom-strings"]) { | |
await loadCustomStrings(args["custom-strings"]) | |
logger.info("Loaded custom strings") | |
} |
delete process.env.CS_LOGIN_TITLE | ||
delete process.env.CS_LOGIN_ENV_PASSWORD_MSG | ||
delete process.env.CS_PASSWORD_PLACEHOLDER | ||
delete process.env.CS_SUBMIT_TEXT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These env vars do not exist anymore, do they?
|
||
// Try to parse as JSON first | ||
try { | ||
customStringsData = JSON.parse(customStringsArg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This automatic JSON/filename handling is really convenient but I worry about overloading the flag like this, especially with error handling since we might return a "file not found" error but really the user just mistyped their JSON and forgot the leading {
, as one example.
I am not familiar with any precedent we can draw on for inspiration, but I have a few ideas:
- We make
--i18n
take a file always, with no way to provide raw JSON (for now). - We make separate
--i18n
and--i18n-json
flags. - We make
--i18n
take a file always, and use an environment variable if you want to pass raw JSON. - We make
--i18n
take a file always, and a new repeatablei18n-var
flag. Usage would becode-server i18n-var "WELCOME=my welcome text" i18n-var "LOGIN_TITLE=my title"
. Something like that. This is kinda nice because there is no need to write JSON on the command line, but it feels a bit clunky.
Thoughts? I think maybe we skip the raw JSON input for now and figure it out later if folks ask for it, unless you feel strongly about including it!
@@ -146,5 +146,70 @@ describe("login", () => { | |||
expect(resp.status).toBe(200) | |||
expect(htmlContent).toContain(`欢迎来到 code-server`) | |||
}) | |||
|
|||
it("should return custom login title", async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like these tests are outdated.
This PR adds comprehensive customization options for the login page, allowing users to customize all text elements through CLI arguments, environment variables, or config files.
🎯 Key Features
--app-name
/--welcome-text
unchanged📋 New CLI Options
🐳 Environment Variables
All CLI options have corresponding
CS_*
environment variables:💼 Use Cases
Docker deployment with branding:
Corporate error messages:
🔧 Implementation Details
🧪 Test Plan
📚 Documentation
docs/install.md
with Docker customization examplesdocs/FAQ.md
with login customization sectiondocs/customization.md
guidedocs/README.md
with link to customization guideThis enables powerful branding and customization for enterprise deployments while maintaining full backwards compatibility.