Public course previewThis is not your assigned passport. No identity, answers, or completion progress are stored here.How to start your passport
Handbook / reference

reference

Euler Tunnel And VS Code

An Euler tunnel connects an interactive tool on your computer, such as VS Code, to an Euler compute node reserved by a Slurm job. Use it only after ordinary SSH access to Euler works. It is not needed for normal unattended batch jobs.

Goal: connect VS Code or SSH to a Slurm compute allocation instead of doing computation on an Euler login node.

Prerequisites: the final public-key-only config-ok alias test in Euler access passes. Do not continue if ssh euler still needs the ETH password.

New to text commands? Read how to open a terminal and run one command before using a command block. It explains the labels used below and what to copy.

Execution context: euler-tunnel config/start/status/stop run on an Euler login-node Bash prompt. SSH files and the tunnel hostname test run on the local computer in the explicitly labelled PowerShell or zsh/Bash block.

What euler-tunnel Does#

euler-tunnel start submits a Slurm job containing an SSH server. Your local Host euler-tunnel entry reaches that allocated compute node through the Euler login service. Installing .vscode-server in your Euler home directory on the first VS Code connection is expected.

Use a tunnel for interactive editing, notebooks, setup, and short debugging. Use sbatch for unattended training, sweeps, and long computation.

1. Generate Personal Configuration#

Run on an Euler login node - Bash:

euler-tunnel config

Expected output:

  • one euler-tunnel ssh-ed25519 ... known-hosts line;
  • one Host euler-tunnel configuration block containing your username and a ProxyCommand.

The generated host key is personal. Copy the output from your own account; do not copy another student's known-hosts line.

2. Add The Known-Hosts Line Locally#

Fetch your own generated output through the verified Host euler alias. The commands below extract only the host-key line, back up an existing file, and do not append a duplicate.

Windows laptop - PowerShell#

& {
    $SshDir = Join-Path $env:USERPROFILE ".ssh"
    $KnownHosts = Join-Path $SshDir "known_hosts"
    New-Item -ItemType Directory -Force $SshDir | Out-Null

    $TunnelOutput = ssh euler "euler-tunnel config"
    if ($LASTEXITCODE -ne 0) { throw "Could not obtain euler-tunnel configuration" }
    $HostKeyLines = @($TunnelOutput | Where-Object { $_ -match '^euler-tunnel\s+ssh-' })
    if ($HostKeyLines.Count -ne 1) { throw "Expected exactly one euler-tunnel host-key line" }

    if (Test-Path $KnownHosts) {
        Copy-Item $KnownHosts "$KnownHosts.backup.$(Get-Date -Format yyyyMMdd-HHmmss)"
    }
    if (-not (Test-Path $KnownHosts) -or
        -not (Select-String -Path $KnownHosts -SimpleMatch $HostKeyLines[0] -Quiet)) {
        if (Test-Path $KnownHosts) {
            $Existing = [System.IO.File]::ReadAllText($KnownHosts)
            if ($Existing.Length -gt 0 -and -not $Existing.EndsWith("`n")) {
                [System.IO.File]::AppendAllText($KnownHosts, [Environment]::NewLine)
            }
        }
        Add-Content $KnownHosts $HostKeyLines[0] -Encoding ascii
    }
    ssh-keygen -F euler-tunnel -f $KnownHosts
}

macOS or Linux laptop - zsh/Bash#

(
  set -eu
  ssh_dir="$HOME/.ssh"
  known_hosts="$ssh_dir/known_hosts"
  mkdir -p "$ssh_dir"
  chmod 700 "$ssh_dir"

  tunnel_output="$(ssh euler 'euler-tunnel config')"
  host_key_lines="$(printf '%s\n' "$tunnel_output" | \
    grep -E '^euler-tunnel[[:space:]]+ssh-')"
  if [ "$(printf '%s\n' "$host_key_lines" | sed '/^$/d' | wc -l | tr -d ' ')" -ne 1 ]; then
    printf 'STOP: expected exactly one euler-tunnel host-key line.\n' >&2
    exit 1
  fi

  if [ -f "$known_hosts" ]; then
    cp -p "$known_hosts" "$known_hosts.backup.$(date +%Y%m%d-%H%M%S)"
  fi
  touch "$known_hosts"
  if ! grep -Fqx "$host_key_lines" "$known_hosts"; then
    if [ -s "$known_hosts" ] &&
       [ "$(tail -c 1 "$known_hosts" | wc -l | tr -d ' ')" -eq 0 ]; then
      printf '\n' >> "$known_hosts"
    fi
    printf '%s\n' "$host_key_lines" >> "$known_hosts"
  fi
  chmod 600 "$known_hosts"
  ssh-keygen -F euler-tunnel -f "$known_hosts"
)

Expected result: ssh-keygen prints one euler-tunnel host-key entry.

3. Add The Tunnel Host In The Existing Include Directory#

The Euler access procedure created ~/.ssh/passport.d/. Use a separate file so the Host euler block cannot be joined accidentally to the tunnel block.

Windows laptop - PowerShell#

& {
    $SshDir = Join-Path $env:USERPROFILE ".ssh"
    $IncludeDir = Join-Path $SshDir "passport.d"
    $BackupDir = Join-Path $SshDir "passport-backups"
    $TunnelConfig = Join-Path $IncludeDir "euler-tunnel.conf"
    $TunnelTemporary = "$TunnelConfig.passport-new"

    $Resolved = @(ssh -G euler 2>$null)
    if ($LASTEXITCODE -ne 0) { throw "STOP: the euler alias does not parse" }
    $UserMatch = $Resolved | Select-String '^user\s+' | Select-Object -First 1
    $EulerUser = if ($UserMatch) { ($UserMatch.Line -split '\s+', 2)[1] } else { "" }
    $IdentityFiles = @($Resolved | ForEach-Object { if ($_ -match '^identityfile\s+(.+)$') { $Matches[1] } })
    $IdentitiesOnlyMatch = $Resolved | Select-String '^identitiesonly\s+' | Select-Object -First 1
    $IdentitiesOnly = if ($IdentitiesOnlyMatch) { ($IdentitiesOnlyMatch.Line -split '\s+', 2)[1] } else { "" }
    if ($EulerUser -notmatch '^[A-Za-z0-9._-]+$') { throw "STOP: the euler alias has no valid short username" }
    if ($IdentityFiles.Count -eq 0 -or @($IdentityFiles | Where-Object { $_ -eq 'none' -or $_ -match '\.pub$' }).Count -gt 0) { throw "STOP: the euler alias has no safe private identity selection" }
    if ($IdentitiesOnly -notin @('yes', 'no')) { throw "STOP: the euler alias has no valid identity policy" }
    $MarkerLines = @(ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no euler "echo config-ok")
    $Marker = if ($MarkerLines.Count -gt 0) { ([string]$MarkerLines[-1]).Trim() } else { "" }
    if ($LASTEXITCODE -ne 0 -or $Marker -ne 'config-ok') { throw "STOP: the required config-ok alias test failed" }

    New-Item -ItemType Directory -Force $IncludeDir, $BackupDir | Out-Null
    if (Test-Path $TunnelConfig) {
        Copy-Item $TunnelConfig (Join-Path $BackupDir "euler-tunnel.conf.$(Get-Date -Format yyyyMMdd-HHmmss)")
    }

    $Lines = @("Host euler-tunnel", "  User $EulerUser")
    foreach ($Identity in $IdentityFiles) {
        if ($Identity.Contains('"')) { throw "STOP: unsupported quote in resolved identity path" }
        $Lines += '  IdentityFile "' + $Identity + '"'
    }
    $Lines += @(
        "  IdentitiesOnly $IdentitiesOnly",
        "  PreferredAuthentications publickey",
        "  PasswordAuthentication no",
        "  KbdInteractiveAuthentication no",
        "  ForwardAgent no",
        "  ServerAliveInterval 10",
        "  ServerAliveCountMax 10",
        "  ProxyCommand ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no euler euler-tunnel connect"
    )
    $Lines | Set-Content $TunnelTemporary -Encoding ascii

    ssh -F $TunnelTemporary -G euler-tunnel | Out-Null
    if ($LASTEXITCODE -ne 0) {
        Remove-Item $TunnelTemporary -ErrorAction SilentlyContinue
        throw "STOP: generated tunnel config is invalid; the existing file is unchanged"
    }
    Move-Item -Force $TunnelTemporary $TunnelConfig
    ssh -G euler-tunnel | Select-String '^(user|identityfile|identitiesonly|preferredauthentications|passwordauthentication|kbdinteractiveauthentication|forwardagent|proxycommand) '
    if ($LASTEXITCODE -ne 0) { throw "STOP: tunnel alias is invalid; restore the timestamped backup" }
}

Do not add the generated ControlMaster, ControlPath, or ControlPersist lines on Windows; they use Unix sockets.

macOS or Linux laptop - zsh/Bash#

(
set -eu
include_dir="$HOME/.ssh/passport.d"
backup_dir="$HOME/.ssh/passport-backups"
tunnel_config="$include_dir/euler-tunnel.conf"
tunnel_temporary="$tunnel_config.passport-new"

resolved="$(ssh -G euler 2>/dev/null)" || { printf 'STOP: the euler alias does not parse\n' >&2; exit 1; }
eth_user="$(printf '%s\n' "$resolved" | awk '$1 == "user" { print $2; exit }')"
case "$eth_user" in ''|*[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-]*) printf 'STOP: the euler alias has no valid short username\n' >&2; exit 1;; esac
identity_files="$(printf '%s\n' "$resolved" | awk '$1 == "identityfile" { $1=""; sub(/^[[:space:]]+/, ""); print }')"
[ -n "$identity_files" ] || { printf 'STOP: the euler alias has no identity selection\n' >&2; exit 1; }
if printf '%s\n' "$identity_files" | awk '$0 == "none" || $0 ~ /[.]pub$/ { bad=1 } END { exit !bad }'; then
  printf 'STOP: the euler alias has no safe private identity selection\n' >&2
  exit 1
fi
identities_only="$(printf '%s\n' "$resolved" | awk '$1 == "identitiesonly" { print $2; exit }')"
case "$identities_only" in yes|no) ;; *) printf 'STOP: the euler alias has no valid identity policy\n' >&2; exit 1;; esac
marker="$(ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no euler 'echo config-ok')" || {
  printf 'STOP: the required config-ok alias test failed\n' >&2
  exit 1
}
[ "$marker" = config-ok ] || { printf 'STOP: the required config-ok marker was not returned\n' >&2; exit 1; }

mkdir -p "$include_dir" "$backup_dir"
chmod 700 "$include_dir" "$backup_dir"
if [ -f "$tunnel_config" ]; then
  cp -p "$tunnel_config" "$backup_dir/euler-tunnel.conf.$(date +%Y%m%d-%H%M%S)"
fi
{
  printf 'Host euler-tunnel\n  User %s\n' "$eth_user"
  while IFS= read -r identity; do
    [ -n "$identity" ] || continue
    case "$identity" in *'"'*) printf 'STOP: unsupported quote in resolved identity path\n' >&2; exit 1;; esac
    printf '  IdentityFile "%s"\n' "$identity"
  done <<EOF
$identity_files
EOF
  printf '  IdentitiesOnly %s\n' "$identities_only"
  printf '  PreferredAuthentications publickey\n  PasswordAuthentication no\n  KbdInteractiveAuthentication no\n  ForwardAgent no\n'
  printf '  ServerAliveInterval 10\n  ServerAliveCountMax 10\n'
  printf '  ProxyCommand ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no euler euler-tunnel connect\n'
  printf '  ControlMaster auto\n  ControlPath ~/.ssh/cs-%%r@%%h:%%p\n  ControlPersist 15\n'
} > "$tunnel_temporary"
chmod 600 "$tunnel_temporary"
ssh -F "$tunnel_temporary" -G euler-tunnel >/dev/null || {
  rm -f "$tunnel_temporary"
  printf 'STOP: generated tunnel config is invalid; the existing file is unchanged\n' >&2
  exit 1
}
mv "$tunnel_temporary" "$tunnel_config"
ssh -G euler-tunnel | grep -E '^(user|identityfile|identitiesonly|preferredauthentications|passwordauthentication|kbdinteractiveauthentication|forwardagent|proxycommand) '
)

Expected result: the resolved user, private identity selection, and identitiesonly policy match the tested euler alias; password and keyboard-interactive authentication are no, forwarding is no, and the proxy command reaches the existing euler alias. If a tunnel configuration already existed, it was backed up and replaced only after the new file parsed successfully.

4. Start The Smallest Suitable Allocation#

Run these only on an Euler login node - Bash.

CPU-only interactive work on es_fuge#

euler-tunnel start --account=es_fuge --cpus-per-task=2 --mem-per-cpu=4G --time=02:00:00

CPU-only public-share work#

euler-tunnel start --account=public --cpus-per-task=2 --mem-per-cpu=4G --time=02:00:00

Short RTX 4090 debugging#

euler-tunnel start --account=es_fuge --gpus=rtx_4090:1 --cpus-per-task=4 --mem-per-cpu=4G --time=00:30:00

Short RTX 3090 debugging#

euler-tunnel start --account=es_fuge --gpus=rtx_3090:1 --cpus-per-task=4 --mem-per-cpu=4G --time=00:30:00

The smaller interactive CPU/memory profile is intentional. Use the batch starter profile in Slurm GPU jobs for representative training, then right-size from measurements.

RTX 4090 is the standard GPU tunnel choice. The lab also has access to two RTX PRO 6000 GPUs, but they require explicit pro_6000 selection and compatible CUDA 13 software. Use their special-purpose batch profile rather than treating them as an interactive fallback.

Check on the Euler login node - Bash:

euler-tunnel status

5. Prove The Tunnel Before Opening VS Code#

Run on your local computer:

ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no euler-tunnel "hostname"

Expected output: a compute-node hostname such as eu-g5-047-2. A key passphrase prompt is normal. An ETH password prompt means the upstream Host euler key setup is not working; stop and fix it.

6. Connect VS Code#

  1. Install the Microsoft Remote - SSH extension locally.
  2. Open the Command Palette.
  3. Select Remote-SSH: Connect to Host....
  4. Select euler-tunnel.
  5. Wait for VS Code Server to install or start in your Euler home directory.
  6. Open your project clone, not the whole /cluster/work/fuge tree.

Only If Terminal SSH Works But VS Code Fails#

Do not change SSH files when the local tunnel test in step 5 still fails. If that test succeeds but VS Code does not connect:

  1. In VS Code, open View > Output and select Remote - SSH.
  2. Check which local SSH configuration file the log says it is using.
  3. If it is not the existing user file that contains Include ~/.ssh/passport.d/*.conf, open local User Settings, search for Remote.SSH: Config File, and enter the full path to that same existing file (normally ~/.ssh/config).
  4. Retry Remote-SSH: Connect to Host... > euler-tunnel.

This setting only tells VS Code which existing file to read; it does not replace or regenerate the file. Do not weaken password settings or add unrelated Remote-SSH compatibility toggles to make the prompt disappear. A key passphrase is expected; an ETH password prompt is not.

The terminal prompt should be a compute node. Verify in the VS Code terminal:

hostname
echo "$SLURM_JOB_ID"

Stop The Allocation#

Run on an Euler login node - Bash when interactive work ends:

euler-tunnel stop

Common Failures And Safe Recovery#

  • Tunnel asks for ETH password: repeat the public-key-only config-ok alias test.
  • Host euler-tunnel is malformed: run ssh -G euler-tunnel; each SSH keyword must be on its own line.
  • Private-key warning names .pub: remove .pub from IdentityFile.
  • VS Code prints download/install logs: wait for listeningOn and successful startup. This is normal on first connection.
  • Terminal tunnel works but VS Code fails: follow the config-file check in step 6; do not regenerate a working SSH key.
  • No tunnel job exists: start it on the Euler login node before connecting.

Ask For Help When#

config-ok succeeds and euler-tunnel status shows a running job, but the local SSH tunnel test still fails. Share the relevant ssh -v euler-tunnel hostname error lines only after removing usernames, private paths, and host details output, never key contents.

Primary Source#

Verified: 2026-08-04. Review by: 2026-11-04. Owner: IDEAL Lab IT.