WHITE LABEL CUSTOMIZATION - nself-org/cli GitHub Wiki
Version: nself v0.8.0 Last Updated: January 29, 2026
Complete guide to white-labeling and customizing nself for agencies, resellers, and B2B SaaS providers.
- Overview
- Core Concepts
- Getting Started
- Brand Customization
- Custom Domains
- Email Templates
- Theme System
- Multi-Tenant Branding
- Admin UI Customization
- Best Practices
- Advanced Customization
- Troubleshooting
White-labeling allows you to rebrand nself as your own product, completely removing or replacing nself branding with your own company identity.
This enables:
- Agencies: Offer branded backend-as-a-service to clients
- Resellers: Sell nself under your brand
- B2B SaaS: Provide whitelabeled infrastructure to customers
- Enterprise: Internal branding for corporate deployments
Agency: "DevStudio"
Client: "Acme Corp"
DevStudio branding:
- Logo: devstudio-logo.svg
- Colors: #FF6B35 (orange)
- Domain: platform.devstudio.io
Client view sees:
- "Powered by DevStudio"
- DevStudio support links
- DevStudio documentation
SaaS Provider: "CloudStack"
Customer: "TechStartup Inc"
Per-customer branding:
- Customer 1: TechStartup branding + techstartup.cloudstack.io
- Customer 2: FinanceApp branding + financeapp.cloudstack.io
- Each customer sees their own brand, not CloudStack
Company: "MegaCorp"
Divisions: Sales, Marketing, Engineering
Shared platform with division branding:
- sales.internal.megacorp.com (Sales branding)
- marketing.internal.megacorp.com (Marketing branding)
- eng.internal.megacorp.com (Engineering branding)
Every visual and textual element can be customized:
- Logos (header, login, favicon)
- Colors (primary, secondary, accent, backgrounds)
- Typography (fonts, sizes, weights)
- Email templates (transactional, marketing)
- Authentication pages (login, signup, password reset)
- Admin dashboard
- Documentation links
- Support contact information
- Legal pages (terms, privacy)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Brand Identity Hierarchy โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ Platform Brand (Top Level) โ
โ โโโ Logo (SVG, PNG) โ
โ โโโ Color Palette โ
โ โ โโโ Primary โ
โ โ โโโ Secondary โ
โ โ โโโ Accent โ
โ โ โโโ Backgrounds โ
โ โโโ Typography โ
โ โ โโโ Font Family โ
โ โ โโโ Heading Styles โ
โ โ โโโ Body Text Styles โ
โ โโโ Themes โ
โ โโโ Light Mode โ
โ โโโ Dark Mode โ
โ โ
โ Tenant Brand (Per-Customer) โ
โ โโโ Inherits Platform Brand โ
โ โโโ Override Logo โ
โ โโโ Override Colors โ
โ โโโ Custom Domain โ
โ โโโ Custom Email Templates โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
| Level | Scope | Use Case |
|---|---|---|
| Platform | Global default | Single-brand deployment |
| Tenant | Per customer | Multi-tenant SaaS |
| Organization | Per org | Enterprise divisions |
| Theme | User preference | Dark/light mode |
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Domain & SSL Architecture โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ Custom Domain Setup โ
โ โโโ Add domain to nself โ
โ โโโ Configure DNS records โ
โ โ โโโ A record โ Server IP โ
โ โ โโโ CNAME for subdomains โ
โ โ โโโ TXT for verification โ
โ โโโ SSL provisioning โ
โ โ โโโ Let's Encrypt (automatic) โ
โ โ โโโ Custom certificate (manual) โ
โ โโโ Nginx routing โ
โ โโโ Route to correct tenant โ
โ โ
โ Wildcard Support โ
โ *.yourdomain.com โ tenant-based routing โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Email Template Structure:
โโโ transactional/
โ โโโ welcome.html
โ โโโ password-reset.html
โ โโโ email-verification.html
โ โโโ invite.html
โโโ marketing/
โ โโโ newsletter.html
โ โโโ announcement.html
โโโ system/
โโโ error-notification.html
โโโ maintenance.html
Variables Available:
- {{user.name}}
- {{user.email}}
- {{company.name}}
- {{company.logo}}
- {{action_url}}
- {{support_email}}
nself uses a CSS variable-based theming system for easy customization:
:root {
/* Primary colors */
--color-primary: #3B82F6;
--color-primary-light: #60A5FA;
--color-primary-dark: #2563EB;
/* Secondary colors */
--color-secondary: #8B5CF6;
--color-accent: #F59E0B;
/* Backgrounds */
--bg-main: #FFFFFF;
--bg-secondary: #F3F4F6;
/* Text */
--text-primary: #111827;
--text-secondary: #6B7280;
/* Fonts */
--font-primary: 'Inter', sans-serif;
--font-heading: 'Poppins', sans-serif;
}- nself v0.5.0+ (white-label features)
- Admin access to nself instance
- Brand assets ready (logos, colors)
- Custom domain(s) available
# Initialize white-label configuration
nself whitelabel init
# Set basic brand information
nself whitelabel branding set \
--name "YourBrand" \
--primary-color "#FF6B35" \
--logo "./assets/logo.svg"
# Add custom domain
nself whitelabel domain add yourbrand.com
# Apply changes
nself whitelabel applyWhen you run nself whitelabel init, it creates .whitelabel/config.json:
{
"version": "1.0",
"platform": {
"name": "YourBrand",
"company": "Your Company Inc",
"website": "https://yourbrand.com",
"support_email": "[email protected]",
"branding": {
"logo": {
"main": "./assets/logo.svg",
"icon": "./assets/icon.svg",
"favicon": "./assets/favicon.ico"
},
"colors": {
"primary": "#FF6B35",
"secondary": "#4ECDC4",
"accent": "#FFE66D"
},
"fonts": {
"primary": "Inter",
"heading": "Poppins"
}
},
"domains": [
{
"domain": "yourbrand.com",
"primary": true,
"ssl": "letsencrypt"
}
]
},
"features": {
"hide_nself_branding": true,
"custom_login_page": true,
"custom_email_templates": true,
"multi_tenant_branding": false
}
}project/
โโโ .whitelabel/
โ โโโ config.json # Main configuration
โ โโโ themes/
โ โ โโโ light.css
โ โ โโโ dark.css
โ โโโ emails/
โ โ โโโ templates/
โ โโโ assets/
โ โ โโโ logo.svg
โ โ โโโ icon.svg
โ โ โโโ favicon.ico
โ โโโ pages/
โ โโโ login.html
โ โโโ terms.html
โโโ branding/ # Generated files (gitignored)
โ โโโ css/
โ โโโ images/
โ โโโ templates/
# 1. Create white-label directory
nself whitelabel init
# 2. Add your brand assets
cp ~/my-brand/logo.svg .whitelabel/assets/
cp ~/my-brand/favicon.ico .whitelabel/assets/
# 3. Configure branding
nself whitelabel branding set \
--name "MyBrand" \
--primary-color "#FF6B35" \
--secondary-color "#4ECDC4" \
--logo ".whitelabel/assets/logo.svg" \
--favicon ".whitelabel/assets/favicon.ico"
# 4. Add custom domain
nself whitelabel domain add mybrand.com \
--ssl letsencrypt \
--primary
# 5. Generate branding files
nself whitelabel generate
# 6. Rebuild with new branding
nself build
nself restart nginx
# 7. Verify branding
nself whitelabel status| Type | Format | Size | Usage |
|---|---|---|---|
| Main Logo | SVG, PNG | 240ร60px | Header, navigation |
| Icon | SVG, PNG | 64ร64px | Small spaces |
| Favicon | ICO, PNG | 32ร32px | Browser tab |
| Email Logo | PNG, JPG | 600ร150px | Email headers |
# Set main logo
nself whitelabel logo set main ./assets/logo.svg
# Set icon (for compact views)
nself whitelabel logo set icon ./assets/icon.svg
# Set favicon
nself whitelabel logo set favicon ./assets/favicon.ico
# Set email logo (optimized for email clients)
nself whitelabel logo set email ./assets/email-logo.png
# View current logos
nself whitelabel logo list{
"branding": {
"logo": {
"main": {
"path": "./assets/logo.svg",
"alt": "YourBrand Logo",
"height": "60px"
},
"icon": {
"path": "./assets/icon.svg",
"size": "64px"
},
"favicon": {
"path": "./assets/favicon.ico"
},
"email": {
"path": "./assets/email-logo.png",
"width": "600px"
}
}
}
}# Set primary color (buttons, links, highlights)
nself whitelabel colors set primary "#FF6B35"
# Set secondary color (secondary actions)
nself whitelabel colors set secondary "#4ECDC4"
# Set accent color (call-to-action, highlights)
nself whitelabel colors set accent "#FFE66D"
# Set background colors
nself whitelabel colors set bg-main "#FFFFFF"
nself whitelabel colors set bg-secondary "#F3F4F6"
# Set text colors
nself whitelabel colors set text-primary "#111827"
nself whitelabel colors set text-secondary "#6B7280"
# Preview colors
nself whitelabel colors preview{
"branding": {
"colors": {
"primary": {
"base": "#FF6B35",
"light": "#FF8C5A",
"dark": "#CC5629",
"contrast": "#FFFFFF"
},
"secondary": {
"base": "#4ECDC4",
"light": "#71D7CF",
"dark": "#3BA39C",
"contrast": "#FFFFFF"
},
"accent": {
"base": "#FFE66D",
"light": "#FFF088",
"dark": "#CCB857",
"contrast": "#111827"
},
"backgrounds": {
"main": "#FFFFFF",
"secondary": "#F3F4F6",
"tertiary": "#E5E7EB",
"dark": "#111827"
},
"text": {
"primary": "#111827",
"secondary": "#6B7280",
"tertiary": "#9CA3AF",
"inverse": "#FFFFFF"
},
"states": {
"success": "#10B981",
"warning": "#F59E0B",
"error": "#EF4444",
"info": "#3B82F6"
}
}
}
}After running nself whitelabel generate, this generates:
/* .whitelabel/themes/light.css */
:root {
/* Primary Colors */
--color-primary: #FF6B35;
--color-primary-light: #FF8C5A;
--color-primary-dark: #CC5629;
--color-primary-contrast: #FFFFFF;
/* Secondary Colors */
--color-secondary: #4ECDC4;
--color-secondary-light: #71D7CF;
--color-secondary-dark: #3BA39C;
--color-secondary-contrast: #FFFFFF;
/* Accent Colors */
--color-accent: #FFE66D;
--color-accent-light: #FFF088;
--color-accent-dark: #CCB857;
--color-accent-contrast: #111827;
/* Backgrounds */
--bg-main: #FFFFFF;
--bg-secondary: #F3F4F6;
--bg-tertiary: #E5E7EB;
--bg-dark: #111827;
/* Text */
--text-primary: #111827;
--text-secondary: #6B7280;
--text-tertiary: #9CA3AF;
--text-inverse: #FFFFFF;
/* States */
--color-success: #10B981;
--color-warning: #F59E0B;
--color-error: #EF4444;
--color-info: #3B82F6;
}# Set primary font (body text)
nself whitelabel fonts set primary "Inter" \
--weights "400,500,600,700" \
--source "google"
# Set heading font
nself whitelabel fonts set heading "Poppins" \
--weights "600,700,800" \
--source "google"
# Set monospace font (code blocks)
nself whitelabel fonts set monospace "Fira Code" \
--weights "400,500" \
--source "google"
# Use custom fonts (self-hosted)
nself whitelabel fonts set primary "CustomFont" \
--source "local" \
--files "./fonts/CustomFont-*.woff2"{
"branding": {
"fonts": {
"primary": {
"family": "Inter",
"source": "google",
"weights": [400, 500, 600, 700],
"fallback": "system-ui, sans-serif"
},
"heading": {
"family": "Poppins",
"source": "google",
"weights": [600, 700, 800],
"fallback": "system-ui, sans-serif"
},
"monospace": {
"family": "Fira Code",
"source": "google",
"weights": [400, 500],
"fallback": "Consolas, Monaco, monospace"
}
},
"typography": {
"scale": "1.2",
"base_size": "16px",
"line_height": "1.5"
}
}
}/* Font imports */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@600;700;800&display=swap');
:root {
/* Font Families */
--font-primary: 'Inter', system-ui, sans-serif;
--font-heading: 'Poppins', system-ui, sans-serif;
--font-monospace: 'Fira Code', Consolas, Monaco, monospace;
/* Font Sizes (Modular Scale 1.2) */
--text-xs: 0.694rem; /* 11px */
--text-sm: 0.833rem; /* 13px */
--text-base: 1rem; /* 16px */
--text-lg: 1.2rem; /* 19px */
--text-xl: 1.44rem; /* 23px */
--text-2xl: 1.728rem; /* 28px */
--text-3xl: 2.074rem; /* 33px */
--text-4xl: 2.488rem; /* 40px */
/* Line Heights */
--leading-tight: 1.25;
--leading-normal: 1.5;
--leading-relaxed: 1.75;
/* Font Weights */
--weight-normal: 400;
--weight-medium: 500;
--weight-semibold: 600;
--weight-bold: 700;
--weight-extrabold: 800;
}For advanced customization beyond variables:
# Add custom CSS file
nself whitelabel css add ./custom-styles.css
# Add inline CSS
nself whitelabel css inline ".custom-class { color: red; }"
# List custom CSS
nself whitelabel css list
# Remove custom CSS
nself whitelabel css remove custom-styles.cssCustom CSS is injected after theme CSS, allowing full override capability.
# Add primary domain
nself whitelabel domain add yourbrand.com \
--ssl letsencrypt \
--primary
# View domain status
nself whitelabel domain status yourbrand.com# Add multiple domains
nself whitelabel domain add app.yourbrand.com --ssl letsencrypt
nself whitelabel domain add api.yourbrand.com --ssl letsencrypt
nself whitelabel domain add admin.yourbrand.com --ssl letsencrypt
# List all domains
nself whitelabel domain list# Add wildcard domain (for multi-tenant)
nself whitelabel domain add "*.yourbrand.com" \
--ssl letsencrypt \
--wildcard
# This enables:
# - customer1.yourbrand.com
# - customer2.yourbrand.com
# - *.yourbrand.comAfter adding a domain, configure DNS:
Type: A
Name: @
Value: YOUR_SERVER_IP
TTL: 3600
Type: CNAME
Name: app
Value: yourbrand.com
TTL: 3600
Type: CNAME
Name: api
Value: yourbrand.com
TTL: 3600
Type: TXT
Name: _nself-verification
Value: VERIFICATION_TOKEN
TTL: 3600
Get verification token:
nself whitelabel domain verify-token yourbrand.com# Provision SSL certificate (automatic renewal)
nself whitelabel ssl provision yourbrand.com
# This will:
# 1. Verify domain ownership
# 2. Request certificate from Let's Encrypt
# 3. Install certificate
# 4. Configure Nginx
# 5. Set up auto-renewal# Use your own certificate
nself whitelabel ssl custom yourbrand.com \
--cert ./certs/yourbrand.crt \
--key ./certs/yourbrand.key \
--chain ./certs/chain.crtBefore SSL provisioning, verify domain points to your server:
# Check domain DNS
nself whitelabel domain check yourbrand.com
# Output:
# โ DNS A record points to 203.0.113.42 (correct)
# โ HTTP reachable on port 80
# โ Domain verification TXT record found
# โ Ready for SSL provisioning{
"domains": [
{
"domain": "yourbrand.com",
"primary": true,
"ssl": {
"provider": "letsencrypt",
"auto_renew": true,
"status": "active",
"expires": "2026-04-29"
},
"verification": {
"method": "txt",
"token": "nself-verify-abc123",
"verified": true
}
},
{
"domain": "*.yourbrand.com",
"wildcard": true,
"ssl": {
"provider": "letsencrypt",
"auto_renew": true,
"status": "active"
}
}
]
}Configure how domains route to services:
# Route domain to specific service
nself whitelabel route add yourbrand.com / frontend
nself whitelabel route add api.yourbrand.com / hasura
nself whitelabel route add admin.yourbrand.com / nself-admin
# View routing table
nself whitelabel route list.whitelabel/emails/
โโโ templates/
โ โโโ transactional/
โ โ โโโ welcome.html
โ โ โโโ password-reset.html
โ โ โโโ email-verification.html
โ โ โโโ invite.html
โ โ โโโ notification.html
โ โโโ marketing/
โ โ โโโ newsletter.html
โ โ โโโ announcement.html
โ โโโ system/
โ โโโ error-notification.html
โ โโโ maintenance.html
โโโ layouts/
โ โโโ base.html
โ โโโ plain.html
โโโ partials/
โ โโโ header.html
โ โโโ footer.html
โ โโโ button.html
โโโ config.json
# Generate default templates
nself whitelabel email init
# This creates all default templates in .whitelabel/emails/Create .whitelabel/emails/templates/transactional/welcome.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to {{company.name}}</title>
<style>
body {
font-family: {{fonts.primary}}, sans-serif;
background-color: #F3F4F6;
margin: 0;
padding: 0;
}
.container {
max-width: 600px;
margin: 40px auto;
background: #FFFFFF;
border-radius: 8px;
overflow: hidden;
}
.header {
background: {{colors.primary}};
padding: 40px 20px;
text-align: center;
}
.logo {
max-width: 200px;
height: auto;
}
.content {
padding: 40px 30px;
}
.button {
display: inline-block;
background: {{colors.primary}};
color: #FFFFFF;
padding: 12px 30px;
text-decoration: none;
border-radius: 6px;
font-weight: 600;
}
.footer {
background: #F3F4F6;
padding: 20px;
text-align: center;
font-size: 14px;
color: #6B7280;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<img src="{{company.email_logo}}" alt="{{company.name}}" class="logo">
</div>
<div class="content">
<h1>Welcome, {{user.name}}!</h1>
<p>We're excited to have you on board. Your account has been successfully created.</p>
<p>Get started by verifying your email address:</p>
<p style="text-align: center; margin: 30px 0;">
<a href="{{action_url}}" class="button">Verify Email</a>
</p>
<p>Or copy this link into your browser:</p>
<p style="word-break: break-all; color: #6B7280; font-size: 14px;">
{{action_url}}
</p>
<p>Need help? Contact us at <a href="mailto:{{support_email}}">{{support_email}}</a></p>
</div>
<div class="footer">
<p>© {{current_year}} {{company.name}}. All rights reserved.</p>
<p>
<a href="{{company.website}}/privacy">Privacy Policy</a> |
<a href="{{company.website}}/terms">Terms of Service</a>
</p>
</div>
</div>
</body>
</html>All templates have access to these variables:
{{user.id}}
{{user.email}}
{{user.name}}
{{user.first_name}}
{{user.last_name}}
{{user.created_at}}
{{company.name}}
{{company.website}}
{{company.logo}}
{{company.email_logo}}
{{support_email}}
{{company.address}}
{{colors.primary}}
{{colors.secondary}}
{{colors.accent}}
{{fonts.primary}}
{{fonts.heading}}
{{action_url}} # Primary CTA link
{{action_text}} # CTA button text
{{verification_code}}
{{reset_token}}
{{current_year}}
{{current_date}}
{{app_name}}
{{app_url}}
Support multiple languages:
# Create language-specific templates
.whitelabel/emails/templates/transactional/
โโโ welcome.en.html
โโโ welcome.es.html
โโโ welcome.fr.html
โโโ welcome.de.html
# Configure language detection
nself whitelabel email config \
--default-language en \
--detect-language user_preferenceTemplate selection logic:
- Use user's language preference
- Fall back to account language
- Fall back to default language (en)
# Preview email template
nself whitelabel email preview welcome \
--user-email "[email protected]" \
--user-name "Test User"
# Send test email
nself whitelabel email test welcome \
--to "[email protected]" \
--variables '{"user.name":"John Doe"}'
# Validate all templates
nself whitelabel email validateConfigure email sending in .whitelabel/emails/config.json:
{
"from": {
"name": "{{company.name}}",
"email": "[email protected]"
},
"reply_to": "{{support_email}}",
"templates": {
"base_url": "/emails/templates",
"default_language": "en",
"languages": ["en", "es", "fr", "de"]
},
"branding": {
"logo": {
"url": "{{company.email_logo}}",
"width": "600px"
},
"colors": {
"primary": "{{colors.primary}}",
"background": "#F3F4F6",
"text": "#111827"
}
},
"footer": {
"show_unsubscribe": true,
"show_privacy_link": true,
"show_address": true,
"custom_links": [
{"text": "Help Center", "url": "{{company.website}}/help"},
{"text": "Contact Us", "url": "{{company.website}}/contact"}
]
}
}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Theme System โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ CSS Variables (Base) โ
โ โโโ Defined in :root โ
โ โ
โ Light Theme โ
โ โโโ Override variables for light mode โ
โ โ
โ Dark Theme โ
โ โโโ Override variables for dark mode โ
โ โ
โ Custom Theme โ
โ โโโ User-defined theme extensions โ
โ โ
โ Component Styles โ
โ โโโ Use CSS variables (theme-agnostic) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Create new theme
nself whitelabel theme create mybrand-light
# This creates:
# .whitelabel/themes/mybrand-light.css.whitelabel/themes/mybrand-light.css:
/* MyBrand Light Theme */
[data-theme="mybrand-light"] {
/* Primary Colors */
--color-primary: #FF6B35;
--color-primary-light: #FF8C5A;
--color-primary-dark: #CC5629;
/* Secondary Colors */
--color-secondary: #4ECDC4;
--color-secondary-light: #71D7CF;
--color-secondary-dark: #3BA39C;
/* Backgrounds */
--bg-main: #FFFFFF;
--bg-secondary: #F9FAFB;
--bg-tertiary: #F3F4F6;
--bg-elevated: #FFFFFF;
/* Text */
--text-primary: #111827;
--text-secondary: #6B7280;
--text-tertiary: #9CA3AF;
/* Borders */
--border-color: #E5E7EB;
--border-light: #F3F4F6;
/* Shadows */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
/* Spacing */
--spacing-unit: 8px;
/* Border Radius */
--radius-sm: 4px;
--radius-md: 6px;
--radius-lg: 8px;
/* Transitions */
--transition-fast: 150ms ease-in-out;
--transition-normal: 250ms ease-in-out;
--transition-slow: 350ms ease-in-out;
}.whitelabel/themes/mybrand-dark.css:
/* MyBrand Dark Theme */
[data-theme="mybrand-dark"] {
/* Primary Colors (slightly adjusted for dark bg) */
--color-primary: #FF8C5A;
--color-primary-light: #FFAD7F;
--color-primary-dark: #FF6B35;
/* Backgrounds */
--bg-main: #111827;
--bg-secondary: #1F2937;
--bg-tertiary: #374151;
--bg-elevated: #1F2937;
/* Text */
--text-primary: #F9FAFB;
--text-secondary: #D1D5DB;
--text-tertiary: #9CA3AF;
/* Borders */
--border-color: #374151;
--border-light: #1F2937;
/* Shadows (more subtle in dark mode) */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
}# List available themes
nself whitelabel theme list
# Set default theme
nself whitelabel theme default mybrand-light
# Enable theme switching
nself whitelabel theme toggle enable
# Preview theme
nself whitelabel theme preview mybrand-dark
# Export theme as CSS
nself whitelabel theme export mybrand-light ./output.cssOverride specific components:
/* .whitelabel/themes/components.css */
/* Buttons */
.button-primary {
background: var(--color-primary);
color: var(--color-primary-contrast);
border-radius: var(--radius-md);
padding: 12px 24px;
font-weight: var(--weight-semibold);
transition: all var(--transition-fast);
}
.button-primary:hover {
background: var(--color-primary-dark);
transform: translateY(-1px);
box-shadow: var(--shadow-md);
}
/* Cards */
.card {
background: var(--bg-elevated);
border: 1px solid var(--border-color);
border-radius: var(--radius-lg);
padding: calc(var(--spacing-unit) * 3);
box-shadow: var(--shadow-sm);
}
/* Forms */
.input {
background: var(--bg-main);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: 10px 14px;
color: var(--text-primary);
transition: border-color var(--transition-fast);
}
.input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.1);
}
/* Navigation */
.navbar {
background: var(--bg-elevated);
border-bottom: 1px solid var(--border-color);
box-shadow: var(--shadow-sm);
}
.nav-link {
color: var(--text-secondary);
transition: color var(--transition-fast);
}
.nav-link:hover,
.nav-link.active {
color: var(--color-primary);
}Generate a preview page to see your theme:
# Generate theme preview
nself whitelabel theme preview-generate
# Opens browser at http://localhost:1337/theme-previewThe preview shows:
- Color palette
- Typography samples
- Button variations
- Form elements
- Cards and containers
- Navigation components
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Multi-Tenant Branding System โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ Platform Level (Default) โ
โ โโโ YourBrand Logo โ
โ โโโ YourBrand Colors โ
โ โโโ YourBrand Domain โ
โ โ
โ Tenant 1: "Acme Corp" โ
โ โโโ Inherits: YourBrand base โ
โ โโโ Override: Logo โ acme-logo.svg โ
โ โโโ Override: Primary Color โ #E02424 โ
โ โโโ Custom Domain: acme.yourbrand.com โ
โ โโโ Custom Emails: Acme branding โ
โ โ
โ Tenant 2: "TechStart Inc" โ
โ โโโ Inherits: YourBrand base โ
โ โโโ Override: Logo โ techstart-logo.svg โ
โ โโโ Override: Colors โ #3B82F6 โ
โ โโโ Custom Domain: techstart.yourbrand.com โ
โ โโโ Custom Emails: TechStart branding โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Enable multi-tenant branding feature
nself whitelabel multi-tenant enable
# This adds tenant branding tables to database
nself whitelabel multi-tenant migrate# Create tenant brand
nself whitelabel tenant create acme-corp \
--name "Acme Corp" \
--logo "./tenants/acme/logo.svg" \
--primary-color "#E02424" \
--domain "acme.yourbrand.com"
# View tenant
nself whitelabel tenant show acme-corp
# List all tenants
nself whitelabel tenant list.whitelabel/tenants/acme-corp.json:
{
"tenant_id": "acme-corp",
"name": "Acme Corp",
"slug": "acme",
"branding": {
"inherit_platform": true,
"overrides": {
"logo": {
"main": "./tenants/acme/logo.svg",
"icon": "./tenants/acme/icon.svg"
},
"colors": {
"primary": "#E02424",
"secondary": "#DC2626"
}
}
},
"domain": {
"primary": "acme.yourbrand.com",
"aliases": ["acme-corp.yourbrand.com"]
},
"emails": {
"from_name": "Acme Corp",
"from_email": "[email protected]",
"reply_to": "[email protected]",
"custom_templates": [
"welcome",
"password-reset"
]
},
"settings": {
"show_platform_branding": false,
"allow_theme_switching": true,
"default_theme": "acme-light"
}
}When a user visits acme.yourbrand.com:
- Nginx detects domain and passes to nself
- nself looks up tenant by domain
- Loads tenant branding from config
- Renders page with tenant-specific branding
Configuration in nginx/sites/wildcard-tenant.conf:
server {
listen 443 ssl;
server_name *.yourbrand.com;
# Pass tenant domain to backend
location / {
proxy_pass http://nself-admin:8080;
proxy_set_header Host $host;
proxy_set_header X-Tenant-Domain $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}Backend tenant detection (pseudo-code):
// In nself-admin or custom service
function getTenantFromRequest(req) {
const domain = req.headers['x-tenant-domain'];
const tenant = db.tenants.findByDomain(domain);
return tenant;
}
function renderWithBranding(tenant) {
const branding = {
...platformBranding,
...tenant.branding.overrides
};
return render(branding);
}Create tenant-specific email templates:
.whitelabel/tenants/acme-corp/emails/
โโโ welcome.html
โโโ password-reset.html
โโโ notification.html
These override platform templates for this tenant only.
# Create tenant email template
nself whitelabel tenant email create acme-corp welcome \
--template ./tenants/acme/emails/welcome.html
# Test tenant email
nself whitelabel tenant email test acme-corp welcome \
--to "[email protected]"Tenants can inherit from platform or override:
| Property | Inherited | Overridable |
|---|---|---|
| Logo | โ Yes | โ Yes |
| Colors | โ Yes | โ Yes |
| Fonts | โ Yes | โ Yes |
| Themes | โ Yes | |
| Email Templates | โ Yes | โ Yes |
| Domain | โ No | โ Required |
| SSL | โ Yes | โ Yes |
Example inheritance:
{
"branding": {
"inherit_platform": true,
"overrides": {
"logo": {
"main": "./tenant-logo.svg"
},
"colors": {
"primary": "#E02424"
// secondary, accent, etc. inherited from platform
}
// fonts inherited from platform
}
}
}# Create tenant
nself whitelabel tenant create TENANT_ID --name "Name"
# Update tenant
nself whitelabel tenant update TENANT_ID --logo ./logo.svg
# Delete tenant
nself whitelabel tenant delete TENANT_ID
# List tenants
nself whitelabel tenant list
# Show tenant details
nself whitelabel tenant show TENANT_ID
# Export tenant config
nself whitelabel tenant export TENANT_ID > tenant.json
# Import tenant config
nself whitelabel tenant import tenant.jsonThe nself-admin UI can be fully customized.
# Set admin logo
nself whitelabel admin logo ./admin-logo.svg
# Set header color
nself whitelabel admin header-color "#FF6B35"
# Set admin title
nself whitelabel admin title "YourBrand Admin"Create custom login page at .whitelabel/pages/login.html:
<!DOCTYPE html>
<html data-theme="mybrand-light">
<head>
<meta charset="UTF-8">
<title>Login - {{company.name}}</title>
<link rel="stylesheet" href="/branding/themes/mybrand-light.css">
<style>
.login-container {
display: flex;
min-height: 100vh;
background: linear-gradient(135deg, {{colors.primary}} 0%, {{colors.secondary}} 100%);
}
.login-box {
margin: auto;
background: var(--bg-main);
padding: 40px;
border-radius: var(--radius-lg);
box-shadow: var(--shadow-lg);
width: 100%;
max-width: 400px;
}
.logo {
text-align: center;
margin-bottom: 30px;
}
.logo img {
max-width: 200px;
height: auto;
}
</style>
</head>
<body>
<div class="login-container">
<div class="login-box">
<div class="logo">
<img src="{{company.logo}}" alt="{{company.name}}">
</div>
<h1 style="text-align: center; margin-bottom: 30px;">Welcome Back</h1>
<form action="/auth/login" method="POST">
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" class="input" required>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" class="input" required>
</div>
<button type="submit" class="button-primary" style="width: 100%; margin-top: 20px;">
Sign In
</button>
</form>
<div style="text-align: center; margin-top: 20px;">
<a href="/auth/forgot-password">Forgot password?</a>
</div>
<div style="text-align: center; margin-top: 30px; color: var(--text-tertiary); font-size: 14px;">
© {{current_year}} {{company.name}}
</div>
</div>
</div>
</body>
</html>Apply custom login page:
nself whitelabel admin page login .whitelabel/pages/login.htmlCustomize admin navigation menu:
# Add custom navigation items
nself whitelabel admin nav add "Help Center" \
--url "https://help.yourbrand.com" \
--icon "help-circle" \
--position 5
# Remove navigation items
nself whitelabel admin nav remove "Documentation"
# Reorder navigation
nself whitelabel admin nav order \
"Dashboard,Projects,Users,Settings,Help Center"Navigation configuration in .whitelabel/admin/nav.json:
{
"navigation": [
{
"id": "dashboard",
"label": "Dashboard",
"icon": "home",
"url": "/admin",
"order": 1
},
{
"id": "projects",
"label": "Projects",
"icon": "folder",
"url": "/admin/projects",
"order": 2
},
{
"id": "help",
"label": "Help Center",
"icon": "help-circle",
"url": "https://help.yourbrand.com",
"external": true,
"order": 5
}
],
"footer": [
{
"label": "Support",
"url": "mailto:{{support_email}}"
},
{
"label": "Privacy",
"url": "{{company.website}}/privacy"
}
]
}Replace nself documentation links with your own:
# Set custom documentation URL
nself whitelabel admin docs-url "https://docs.yourbrand.com"
# Set custom support URL
nself whitelabel admin support-url "https://support.yourbrand.com"
# Set custom status page
nself whitelabel admin status-url "https://status.yourbrand.com"This updates all "Learn more" and "Get help" links throughout the admin UI.
Customize admin dashboard:
# Remove default widgets
nself whitelabel admin dashboard remove-widget "nself-news"
# Add custom widget
nself whitelabel admin dashboard add-widget \
--type "iframe" \
--title "Company Announcements" \
--url "https://yourbrand.com/announcements/embed" \
--width "full" \
--order 1Define all design values in one place:
{
"design_tokens": {
"colors": {
"primary": "#FF6B35",
"secondary": "#4ECDC4"
},
"spacing": {
"unit": 8,
"scale": [0, 8, 16, 24, 32, 40, 48, 64, 80]
},
"typography": {
"scale": 1.2,
"base_size": 16
}
}
}Then reference these tokens everywhere:
- CSS variables
- Email templates
- Email signatures
- PDF exports
- Mobile apps
Create .whitelabel/BRAND-GUIDELINES.md:
# YourBrand Brand Guidelines
## Logo Usage
- Minimum size: 120px wide
- Clear space: 24px on all sides
- Do not stretch or distort
- Use primary logo on light backgrounds
- Use white logo on dark backgrounds
## Color Palette
Primary: #FF6B35 - Use for CTAs, links, primary actions
Secondary: #4ECDC4 - Use for secondary actions, highlights
Accent: #FFE66D - Use sparingly for emphasis
## Typography
Headings: Poppins, 600-800 weight
Body: Inter, 400-600 weight
Never use more than 2 font families
## Voice & Tone
- Professional but approachable
- Clear and concise
- Action-oriented
- Avoid jargon# Use SVG for logos (scales perfectly, small file size)
# If using PNG:
# - Use transparent background
# - Optimize with tools like ImageOptim or TinyPNG
# - Provide @2x versions for retina displays
# Example sizes:
logo.svg # Vector, any size
logo.png # 240x60px
[email protected] # 480x120px
logo-email.png # 600x150px (PNG for email compatibility)Only override what's necessary:
/* โ Bad: Overriding everything */
.button {
background: #FF6B35;
color: white;
padding: 12px 24px;
border: none;
border-radius: 6px;
/* ...50 more lines */
}
/* โ
Good: Only override specific values */
.button-primary {
background: var(--color-primary);
border-radius: var(--radius-md);
}This allows runtime theme switching without loading additional CSS:
/* โ
Good: Uses variables */
.card {
background: var(--bg-elevated);
border: 1px solid var(--border-color);
}
/* โ Bad: Hardcoded colors */
.card {
background: #FFFFFF;
border: 1px solid #E5E7EB;
}<!-- Load fonts with display=swap to prevent blocking -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">All custom branding must work on mobile:
.logo {
max-width: 200px;
height: auto;
}
@media (max-width: 768px) {
.logo {
max-width: 140px;
}
}
/* For very small screens, use icon only */
@media (max-width: 480px) {
.logo-full {
display: none;
}
.logo-icon {
display: block;
max-width: 40px;
}
}<!-- Use responsive email template -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
/* Mobile styles */
@media only screen and (max-width: 600px) {
.container {
width: 100% !important;
padding: 20px !important;
}
.button {
width: 100% !important;
display: block !important;
}
}
</style># Use nself testing tools
nself whitelabel test mobile
# Opens preview with device simulators:
# - iPhone 13
# - Samsung Galaxy S21
# - iPadEnsure sufficient contrast (WCAG AA minimum):
# Check color contrast
nself whitelabel accessibility check-contrast
# Output:
# โ Primary color on white: 4.52:1 (WCAG AA Pass)
# โ Secondary text on primary: 2.1:1 (WCAG AA Fail)
# Suggestion: Darken text to #1F2937 for 4.5:1 ratio<!-- โ
Good: Descriptive alt text -->
<img src="/logo.svg" alt="YourBrand - Backend as a Service">
<!-- โ Bad: Generic or missing alt text -->
<img src="/logo.svg" alt="Logo">Ensure interactive elements have visible focus states:
.button:focus {
outline: 3px solid var(--color-primary);
outline-offset: 2px;
}
.input:focus {
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.1);
}Create tenant-specific onboarding:
# Create onboarding template
nself whitelabel onboarding create \
--template "./onboarding/welcome-flow.json"
# Show branded tutorial on first login
nself whitelabel onboarding enable --for-new-usersExample onboarding flow:
{
"steps": [
{
"id": "welcome",
"title": "Welcome to {{company.name}}!",
"content": "Let's get you started.",
"image": "{{company.logo}}"
},
{
"id": "setup-profile",
"title": "Complete Your Profile",
"action": "redirect:/profile/edit"
},
{
"id": "first-project",
"title": "Create Your First Project",
"action": "redirect:/projects/new"
}
]
}Send branded welcome email on tenant creation:
nself whitelabel tenant create new-customer \
--name "New Customer" \
--send-welcome-email
# Uses custom welcome template with tenant brandingOverride all auth pages:
# Create custom auth pages
.whitelabel/pages/
โโโ login.html
โโโ signup.html
โโโ forgot-password.html
โโโ reset-password.html
โโโ verify-email.html
# Apply to auth service
nself whitelabel auth pages-dir .whitelabel/pages/Brand PDF exports (invoices, reports):
# Configure PDF templates
nself whitelabel pdf template invoice \
--header "./pdf/header.html" \
--footer "./pdf/footer.html" \
--css "./pdf/styles.css"PDF header template:
<!-- .whitelabel/pdf/header.html -->
<div style="display: flex; justify-content: space-between; padding: 20px; border-bottom: 2px solid {{colors.primary}};">
<img src="{{company.logo}}" style="height: 40px;" alt="{{company.name}}">
<div style="text-align: right;">
<strong>{{document.type}}</strong><br>
{{document.number}}<br>
{{document.date}}
</div>
</div>Even API responses can be branded:
# Configure API metadata
nself whitelabel api metadata \
--name "{{company.name}} API" \
--docs-url "https://docs.yourbrand.com/api" \
--support-email "{{support_email}}"API responses include branding:
{
"data": {...},
"meta": {
"powered_by": "YourBrand API",
"docs": "https://docs.yourbrand.com/api",
"support": "[email protected]"
}
}For complete white-labeling, configure mobile apps:
# Generate mobile app config
nself whitelabel mobile init
# Configure iOS
nself whitelabel mobile ios \
--app-name "YourBrand" \
--bundle-id "com.yourbrand.app" \
--icon "./mobile/icon-ios.png"
# Configure Android
nself whitelabel mobile android \
--app-name "YourBrand" \
--package-name "com.yourbrand.app" \
--icon "./mobile/icon-android.png"
# Export configuration
nself whitelabel mobile export ./mobile-config.jsonRoute different features to different subdomains:
# Configure feature-based subdomains
nself whitelabel subdomain add app.yourbrand.com \
--routes "/, /dashboard, /projects"
nself whitelabel subdomain add api.yourbrand.com \
--service hasura
nself whitelabel subdomain add admin.yourbrand.com \
--service nself-admin
nself whitelabel subdomain add docs.yourbrand.com \
--proxy "https://your-docs-site.com"Problem: Logo doesn't show up after setting
Solutions:
# 1. Check file path is correct
nself whitelabel logo verify
# 2. Ensure file is accessible
ls -la .whitelabel/assets/logo.svg
# 3. Regenerate branding files
nself whitelabel generate --force
# 4. Clear browser cache
# CMD+Shift+R (Mac) or CTRL+Shift+R (Windows)Problem: SSL certificate provisioning fails
Solutions:
# 1. Verify DNS is correct
nself whitelabel domain check yourbrand.com
# 2. Check domain verification
nself whitelabel domain verify yourbrand.com
# 3. Retry SSL provisioning
nself whitelabel ssl provision yourbrand.com --force
# 4. Check Let's Encrypt rate limits
# (50 certs per domain per week)
# 5. Use manual certificate as fallback
nself whitelabel ssl custom yourbrand.com \
--cert ./cert.pem \
--key ./key.pemProblem: Emails still show default template
Solutions:
# 1. Validate template syntax
nself whitelabel email validate welcome
# 2. Check variables are correct
nself whitelabel email variables welcome
# 3. Clear email template cache
nself whitelabel email cache clear
# 4. Send test email
nself whitelabel email test welcome \
--to "[email protected]" \
--debugProblem: Custom theme doesn't take effect
Solutions:
# 1. Check theme is registered
nself whitelabel theme list
# 2. Set as default
nself whitelabel theme default mybrand-light
# 3. Regenerate theme CSS
nself whitelabel theme generate mybrand-light --force
# 4. Clear CSS cache
nself whitelabel cache clear css
# 5. Check browser isn't caching
# Force refresh: CMD+Shift+RProblem: Tenant domain doesn't route correctly
Solutions:
# 1. Check tenant configuration
nself whitelabel tenant show tenant-id
# 2. Verify domain is added
nself whitelabel domain list | grep tenant-domain
# 3. Check nginx configuration
nself logs nginx | grep "tenant-domain"
# 4. Regenerate nginx configs
nself build --services nginx
nself restart nginx
# 5. Test routing manually
curl -H "Host: tenant.yourbrand.com" http://localhost# Check all white-label configuration
nself whitelabel status --verbose
# Validate configuration
nself whitelabel validate
# Test specific tenant
nself whitelabel test tenant acme-corp
# View generated files
nself whitelabel files list
# Export all branding
nself whitelabel export ./backup.tar.gz
# Import branding backup
nself whitelabel import ./backup.tar.gzIf you encounter issues:
- Check logs:
nself logs --service nginx,nself-admin - Run diagnostics:
nself whitelabel diagnose - Check documentation:
nself whitelabel docs - Community forum: https://community.nself.org
- File issue: https://github.com/nself-org/cli/issues
White-labeling nself enables complete brand customization for:
- Agencies offering branded backend services
- Resellers selling under their own brand
- B2B SaaS with per-customer branding
- Enterprise internal divisions
- Start simple: Logo + colors + domain
- Expand gradually: Email templates, themes, multi-tenant
- Test thoroughly: Mobile, accessibility, email clients
- Document branding: Create brand guidelines
- Performance matters: Optimize assets, use CSS variables
- Consistency is key: Use design tokens everywhere
# 1. Initialize white-label
nself whitelabel init
# 2. Set basic branding
nself whitelabel branding set --name "YourBrand"
# 3. Add custom domain
nself whitelabel domain add yourbrand.com
# 4. Customize theme
nself whitelabel theme create mybrand-light
# 5. Apply and test
nself whitelabel apply
nself whitelabel testFor additional examples and templates, see:
- GitHub: https://github.com/nself-org/cli-examples/whitelabel
- Templates: https://templates.nself.org/whitelabel
Version: nself v0.8.0 Last Updated: January 29, 2026 License: MIT
For more information, visit nself.org or join our community at community.nself.org.