Automatically Change Terminal Colors When SSHing to Different Hosts


3 views

As a developer constantly juggling between production, staging, and development servers through SSH, I've often found myself running dangerous commands on the wrong server. The visual monotony of terminal windows makes it dangerously easy to confuse environments. What we need is automatic terminal theming based on SSH destinations.

We'll implement this through a combination of SSH configuration tricks and shell scripting. The core components are:

1. ~/.ssh/config host definitions
2. Terminal escape sequences for color changes
3. Bash PROMPT_COMMAND or ZSH hooks
4. Local configuration files for color schemes

First, let's set up our SSH config with identifiable host aliases:

# ~/.ssh/config
Host prod-web
    HostName 192.168.1.100
    User admin
    IdentityFile ~/.ssh/prod_key
    SetEnv TERM_COLOR_SCHEME=red

Host staging-db 
    HostName staging.example.com
    User dbadmin
    SetEnv TERM_COLOR_SCHEME=blue

We'll use ANSI escape codes to modify terminal colors. Create a script called ~/.terminal_colors:

#!/bin/bash
case $TERM_COLOR_SCHEME in
    red)
        printf "\033]11;#330000\033\\"  # background
        printf "\033]10;#ffdddd\033\\"  # foreground
        ;;
    blue)
        printf "\033]11;#000033\033\\"
        printf "\033]10;#ddddff\033\\"
        ;;
    *)
        printf "\033]11;#000000\033\\"  # default
        printf "\033]10;#ffffff\033\\"
        ;;
esac

For bash users, add this to your ~/.bashrc:

function set_term_color() {
    if [ -n "$TERM_COLOR_SCHEME" ]; then
        source ~/.terminal_colors
    fi
}

PROMPT_COMMAND="set_term_color;$PROMPT_COMMAND"

For zsh users, add to ~/.zshrc:

autoload -U add-zsh-hook
add-zsh-hook precmd set_term_color

For more complex setups, create JSON configuration files:

// ~/.terminal_themes/prod-web.json
{
    "background": "#330000",
    "foreground": "#ffdddd",
    "cursor": "#ff0000",
    "highlight": "#550000"
}

Then modify your script to parse these:

#!/bin/bash
if [ -n "$TERM_COLOR_SCHEME" ]; then
    CONFIG_FILE="$HOME/.terminal_themes/${TERM_COLOR_SCHEME}.json"
    if [ -f "$CONFIG_FILE" ]; then
        bg=$(jq -r '.background' "$CONFIG_FILE")
        fg=$(jq -r '.foreground' "$CONFIG_FILE")
        printf "\033]11;${bg}\033\\"
        printf "\033]10;${fg}\033\\"
    fi
fi

For Windows users with WSL or Git Bash, use these escape sequences instead:

printf "\e]4;0;$bg_color\a"  # background
printf "\e]4;1;$fg_color\a"  # foreground

Be cautious when:

  • Allowing servers to set TERM_COLOR_SCHEME via AcceptEnv
  • Using untrusted JSON parsers for theme files
  • Making color schemes too distinctive (could expose sensitive info)

If colors aren't changing:

1. Verify $TERM_COLOR_SCHEME is set: echo $TERM_COLOR_SCHEME
2. Check escape sequence support: echo -e "\033]11;#ff0000\033\\"
3. Confirm PROMPT_COMMAND is working: echo $PROMPT_COMMAND
4. Test script directly: source ~/.terminal_colors

For tmux users, you can theme entire sessions:

# ~/.tmux.conf
bind-key -n M-c run-shell "tmux set-window-option window-status-current-style bg=$TMUX_COLOR"

Then set TMUX_COLOR in your SSH config like we did with TERM_COLOR_SCHEME.


As a developer constantly hopping between servers, I've found myself in situations where I accidentally typed production commands in a staging environment - all because my terminal windows looked identical. This isn't just about aesthetics; it's about preventing costly mistakes.

The most elegant solution leverages your ~/.ssh/config file combined with terminal emulator features. Here's how to implement it in iTerm2 (macOS) or compatible terminals:

# ~/.ssh/config example
Host production-*
  HostName %h.example.com
  User deploy
  RemoteCommand echo -e "\033]50;SetProfile=Production\a"
  RequestTTY force

Host staging-*
  HostName %h.staging.example.com
  User developer
  RemoteCommand echo -e "\033]50;SetProfile=Staging\a"
  RequestTTY force

For iTerm2 Users

Create color profiles named "Production" (red background) and "Staging" (yellow background) in iTerm preferences. The escape sequence \033]50;SetProfile=ProfileName\a triggers the switch.

Gnome Terminal Solution

# In your ~/.bashrc or server-side profile
if [ -n "$SSH_CONNECTION" ]; then
  case "$HOSTNAME" in
    production*) printf "\e]11;#400000\a" ;;
    staging*) printf "\e]10;#000000\a\e]11;#FFFFCC\a" ;;
  esac
fi

For more control, create a wrapper script:

#!/bin/bash
# ssh-theme.sh
case "$1" in
  prod*)
    telliterm "Production"
    ssh -t user@production-server "$2"
    telliterm "Default"
    ;;
  stage*)
    telliterm "Staging" 
    ssh -t user@staging-server "$2"
    telliterm "Default"
    ;;
esac

function telliterm() {
  echo -ne "\033]50;SetProfile=$1\a"
}

If you use tmux across sessions, set different status bar colors:

# In ~/.tmux.conf
bind-key P select-pane -P 'bg=colour52,fg=white'
bind-key S select-pane -P 'bg=colour58,fg=white'

Remember that any server-side color changes could potentially be exploited (like hiding malicious commands in white text). Client-side solutions are generally safer.