How to connect SSH (Secure Shell) with Java

SSH (Secure Shell) is a helpful protocol for remote access and transferring files between the SSH server and the client.

Java can execute commands, shell scripts, or transfer files on the server.

Use case scenario: An administrator of a web application client wants to do a task, but The Task needs to execute crontab or shell scripts on the server. The developer can design a web page to support this requirement by creating an admin page with a button for the administrator to click to execute it. This can provide an easy way for administrators to execute commands or shell scripts without knowledge of Linux or Unix OS.

For example, connect to SSH (Secure Shell).

This example creates a Java client to connect to the SSH server.

private static Session setupJsch() throws JSchException {
    String server = "localhost";
    int port = 22;
    String user = "admin";
    String pass = "password";
    JSch jsch = new JSch();
    jsch.setKnownHosts("C:/Users/nithidol.v/.ssh/known_hosts_web");
    //generate the known_hosts file using the following command:
    //ssh-keyscan -H -t rsa REMOTE_HOSTNAME >> known_hosts_web
    //copy keyscan to c:/Users/user_name/.ssh/known_hosts_web
    Session jschSession = jsch.getSession(user, server, port);
    jschSession.setPassword(pass);
    System.out.println("#connect begin.");
    jschSession.connect();
    System.out.println("#connect end.");
    return jschSession;
}

Connect without KnownHosts

Developers who deploy projects on the server can avoid generating KnownHosts by adding configurations.

jschSession.setConfig("StrictHostKeyChecking", "no");

The algorithm negotiation fails.

Developers connect to SSH and then encounter a problem, Algorithm.

Algorithm negotiation fail: algorithmName="cipher.c2s" jschProposal="aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com" serverProposal="aes128-cbc,aes256-cbc"

Developers can add more Algorithms by adding configuration.

java.util.Properties config = new java.util.Properties();
config.put("cipher.c2s", "aes128-cbc,aes256-cbc");
config.put("cipher.s2c", "aes128-cbc,aes256-cbc");

jschSession.setConfig(config);

Timeout configuration

Developers can configure the timeout to wait for a server response for any longer to prevent a timeout when a server is busy in a network with heavy traffic.

jschSession.setTimeout(120000); //2 minutes

Example execute command.

public static void listFile() throws JSchException, IOException {
    Session session = setupJsch();
    ChannelExec channel = (ChannelExec) session.openChannel("exec");
    channel.setCommand("ls -l");
    channel.connect();

    // Read the command output
    InputStream in = channel.getInputStream();
    byte[] tmp = new byte[1024];
    while (true) {
        while (in.available() > 0) {
            int i = in.read(tmp, 0, 1024);
            if (i < 0) {
                break;
            }
            System.out.print(new String(tmp, 0, i));
        }
        if (channel.isClosed()) {
            if (in.available() > 0) {
                continue;
            }
            System.out.println("Exit status: " + channel.getExitStatus());
            break;
        }
    }

    channel.disconnect();
    session.disconnect();
    System.exit(0);
}

Example: Execute shell scripts.

public static void executeShellScript() throws JSchException, IOException {
    String remoteScriptPath = "/path/on/remote/server/script.sh";
    Session session = setupJsch();
    ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
    InputStream scriptInputStream = new FileInputStream(remoteScriptPath);
    channelExec.setCommand("bash");
    channelExec.setInputStream(scriptInputStream);
    channelExec.connect();
    scriptInputStream.close();
    channelExec.disconnect();
    session.disconnect();
    System.exit(0);
}

For example, execute a crontab for a schedule.

public static void executeCrontab() throws JSchException {
    String cronExpression = "*/5 * * * *"; // Example: Run every 5 minutes
    Session session = setupJsch();
    ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
    channelExec.setCommand("echo \"" + cronExpression + " /path/to/remote/script.sh\" | crontab -");
    channelExec.connect();
    channelExec.disconnect();
    session.disconnect();
    System.exit(0);
}

For example, create a non-existent directory.

private static void createDirectory(ChannelSftp channelSftp, String path) throws SftpException {
    String[] folders = path.split("/");
    StringBuilder currentPath = new StringBuilder();
    for (String folder : folders) {
        if (!folder.isEmpty()) {
            currentPath.append("/").append(folder);
            try {
                channelSftp.cd(currentPath.toString());
            } catch (Exception e) {
                channelSftp.mkdir(currentPath.toString());
            }
        }
    }
}

For example, upload files.

public void uploadFile(String source, String remoteFilePath) throws Exception {
    ChannelSftp channelSftp = setupJsch();
    channelSftp.connect();
    File f = new File(source); // D:/reports/example.csv
    log.debug("source=" + f.getAbsolutePath());
    log.debug("remotePath=" + remoteFilePath + "/" + f.getName()); // /report/date_YYYYMMdd/example.csv
    channelSftp.put(f.getAbsolutePath(), remoteFilePath + "/" + f.getName());
    log.debug(source + " has uploaded.");
    channelSftp.exit();
}

How to close a program in Java

The System.exit() method terminates the JVM. You can pass an exit status code:

  • 0: Indicates normal termination.
  • Non-zero values (e.g., 1): Indicate abnormal termination or errors.

Finally

SSH (Secure Shell) can be used for multiple purposes, such as the CI/CD Integration Pipeline. The developer should learn Linux and UNIX commands. It is helpful for the developer using a Java SSH client to manage and maintain the server.