Curriculum 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

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

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

Prerequisites: the public-key-only key-ok test in Euler access passes. Do not continue if Euler still needs the ETH password for that test.

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/config.d/. Use a separate file so the Host euler block cannot be joined accidentally to the tunnel block.

Windows laptop - PowerShell#

& {
    $User = Read-Host "ETH username"
    if ($User -notmatch '^[A-Za-z0-9._-]+$') { throw "Invalid ETH username" }
    $SshDir = Join-Path $env:USERPROFILE ".ssh"
    $IncludeDir = Join-Path $SshDir "config.d"
    $KeyPath = Join-Path $SshDir "id_ed25519_euler"
    $TunnelConfig = Join-Path $IncludeDir "euler-tunnel.conf"
    if (-not (Test-Path $KeyPath)) { throw "Missing private key: $KeyPath" }
    New-Item -ItemType Directory -Force $IncludeDir | Out-Null
    if (Test-Path $TunnelConfig) {
        Copy-Item $TunnelConfig "$TunnelConfig.backup.$(Get-Date -Format yyyyMMdd-HHmmss)"
    }

    @"
Host euler-tunnel
  User $User
  IdentityFile ~/.ssh/id_ed25519_euler
  IdentitiesOnly yes
  ServerAliveInterval 10
  ServerAliveCountMax 10
  ProxyCommand ssh euler euler-tunnel connect
"@ | Set-Content $TunnelConfig -Encoding ascii

    ssh -G euler-tunnel | Select-String '^(user|identityfile|proxycommand) '
}

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

macOS or Linux laptop - zsh/Bash#

(
set -eu
printf 'ETH username: '
read -r eth_user
case "$eth_user" in
  ''|*[!A-Za-z0-9._-]*) printf 'STOP: invalid ETH username\n' >&2; exit 1 ;;
esac
include_dir="$HOME/.ssh/config.d"
tunnel_config="$include_dir/euler-tunnel.conf"
test -f "$HOME/.ssh/id_ed25519_euler"
mkdir -p "$include_dir"
if [ -f "$tunnel_config" ]; then
  cp -p "$tunnel_config" "$tunnel_config.backup.$(date +%Y%m%d-%H%M%S)"
fi
cat > "$tunnel_config" <<EOF
Host euler-tunnel
  User $eth_user
  IdentityFile ~/.ssh/id_ed25519_euler
  IdentitiesOnly yes
  ServerAliveInterval 10
  ServerAliveCountMax 10
  ProxyCommand ssh euler euler-tunnel connect
  ControlMaster auto
  ControlPath ~/.ssh/cs-%r@%h:%p
  ControlPersist 15
EOF
chmod 600 "$tunnel_config"
ssh -G euler-tunnel | grep -E '^(user|identityfile|proxycommand) '
)

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 config.d/*, 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 key-ok 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#

key-ok succeeds and euler-tunnel status shows a running job, but the local SSH tunnel test still fails. Share sanitized ssh -v euler-tunnel hostname output, never key contents.

Primary Source#

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