SSH into dynamic remote server and run a command - Laravel 5.8 - php

I'm using L 5.8 and I have a form with 3 inputs
Right now, I can SSH into a specific server with this package laravelcollective/remote": "~5.8. I required to pre configured IP, UN, PW in the config/remote.php like so :
'connections' => [
'production' => [
'host' => '1.1.1.1',
'username' => 'code',
'password' => '8888',
'key' => '',
'keytext' => '',
'keyphrase' => '',
'agent' => '',
'timeout' => 10,
],
],
Then, I can easily run any command(s) or even chain them
$commands = ['cd /home/code && ./runMe.sh'];
SSH::run($commands, function($line)
{
echo $line.PHP_EOL;
});
Result
My portal will connect to that server and run that command successfully, and I've verified it.
Now
I need to read it from form inputs. Is it possible to use the same plugin and dynamically setting that file remote.php ?
or
Should I start looking into something else because this is a dead end ?
Please advise,

You can use the config() helper here:
example config:
config([
'remote.connections.production.host' => $request->input('hostname'),
'remote.connections.production.username' => $request->input('username'),
'remote.connections.production.password' => $request->input('password')
]);
then call:
$commands = ['cd /home/code && ./runMe.sh'];
SSH::run($commands, function($line)
{
echo $line.PHP_EOL;
});

This example require the package php-ssh2, and provide many ways to retrieve the remote shell STDOUT as a stream. It's also great to control the current machine shell and get responses.
sudo apt install php-ssh2
Or by version:
sudo apt install php7.4-ssh2
Example usage of ssh2_exec() and ssh2_fetch_stream():
<?php
$ssh = ssh2_connect('192.162.68.212', 22); // Remote address
ssh2_auth_password($ssh, 'root', 'XQA8DCamdEm'); // Credentials
$shell = ssh2_shell($ssh, 'xterm'); // Choose remote shell
$stream = ssh2_exec($ssh, 'cd /home/code && ./runMe.sh'); // Remote command
stream_set_blocking($stream, true); // Wait for multiline output, till EOF
$stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO); // SSH2_STREAM_STDERR
echo stream_get_contents($stream_out); // Print in real-time
It is possible to retrieve only the errors, this is great for monitoring only without parsing the whole output, by using the flag SSH2_STREAM_STDERR.
To write strings only to STDERR from the remote PHP, we can use:
fwrite(STDERR, "Some logs, from machine (...)\n");
Or we can pipe the errors directly in the remote shell command:
cd /home/code && ./runMe.sh 2>
https://www.php.net/manual/en/ref.ssh2.php

Related

AWS EC2 Apache User Cannot run php exec

I am using the following PHP script to send an email from my server. I need to send an email to the admin when a new record is created in the DB. So within the same php script that updates the DB, I want to trigger the other script that sends the email.
Problem is no matter what I do, apache will not execute the email script when requested from the web/api.
However, when I run php sendemail.php from the command line it works. Also when I run php updatedb.php which includes the exec('php sendemail.php') also works from the command line (these are all executed with root "ec2-user").
Things I tried:
I checked the disabled functions in php.ini and it is empty, nothing is disabled.
I tried changing file permissions to include 'x' for the apache group still no go.
I tried replacing exec with shell_exec, and include, no luck.
Here is 'sendemail.php':
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php';
use Aws\Ses\SesClient;
use Aws\Exception\AwsException;
$SesClient = new SesClient([
'profile' => 'default',
'version' => '2010-12-01',
'region' => 'us-west-2'
]);
$sender_email = 'sender#example.com';
$recipient_emails = ['recipient1#example.com','recipient2#example.com'];
$configuration_set = 'ConfigSet';
$subject = 'Amazon SES test (AWS SDK for PHP)';
$plaintext_body = 'This email was sent with Amazon SES using the AWS SDK for PHP.' ;
$html_body = '<h1>AWS Amazon Simple Email Service Test Email</h1>'.
'<p>This email was sent with <a href="https://aws.amazon.com/ses/">'.
'Amazon SES</a> using the <a href="https://aws.amazon.com/sdk-for-php/">'.
'AWS SDK for PHP</a>.</p>';
$char_set = 'UTF-8';
try {
$result = $SesClient->sendEmail([
'Destination' => [
'ToAddresses' => $recipient_emails,
],
'ReplyToAddresses' => [$sender_email],
'Source' => $sender_email,
'Message' => [
'Body' => [
'Html' => [
'Charset' => $char_set,
'Data' => $html_body,
],
'Text' => [
'Charset' => $char_set,
'Data' => $plaintext_body,
],
],
'Subject' => [
'Charset' => $char_set,
'Data' => $subject,
],
],
'ConfigurationSetName' => $configuration_set,
]);
$messageId = $result['MessageId'];
echo("Email sent! Message ID: $messageId"."\n");
} catch (AwsException $e) {
// output error message if fails
echo $e->getMessage();
echo("The email was not sent. Error message: ".$e->getAwsErrorMessage()."\n");
echo "\n";
}
a short version of the updatedb.php file, omitting all transactions:
<?php
exec('php send_email.php', $sendEmail);
require_once 'response.php';
$response = new response();
$response->setHttpStatusCode(201);
$response->setSuccess(true);
$response->addMessage('DB Record Inserted successfully ::: ');
$response->setData($sendEmail);
$response->send();
?>
in the updatedb.php file, if I change the first line to echo exec('whoami') and hit it from the web it works. Which is what I am looking for exactly except that I want to work for php sendemail.php
Environment: AWS EC2 Amazon Linux 2 AMI. PHP 7.2.34
I hope it is clear. I am beginner with linux. Please help. Thanks in advance to all.
Thank you so much #Riz your tip about sudo -u apache php sendemail.php saved my day! I was able to debug on the command line and it turns out that my mistake was with the line require 'vendor/autoload.php'; in my original sendemail.php script I was requiring the file from a directory that did not belong to the apache group. So, once I moved the vendor folder to the same folder as the sendemail.php script file everything worked great!
Lesson learned: Make sure all required/included files belong to the apache group. There was no need to grant apache any execution permissions on any file.

How to run SSH command using Laravel Envoy

I want to run SSH command to start/stop Server with Laravel Envoy on Linux. But the am getting error for syntax of SSH::into(). I don't know what to do completely stuck. Need way to solve this and make this works.
Envoy setup and works fine with "php artisan" command:
// Envoy.blade.php
#setup
$connection = ['web' => $user.'#'.$host.' -p '. '22'];
#endsetup
#servers($connection)
#task('foo', ['on' => 'web'])
php artisan
#endtask
Command: envoy run foo --user=root --host=94.130.97.242
And this is what am doing for SSH::into() to start/stop server.
// Envoy.blade.php
#include('vendor/autoload.php')
$connection = ['web' => $user.'#'.$host.' -p '. '22'];
$target = [
'host' => $host,
'username' => $user,
'password' => $password,
'timeout' => 10,
];
Config::set('remote.connections.runtime.host', $target['host']);
Config::set('remote.connections.runtime.port', '22');
Config::set('remote.connections.runtime.username', $target['username']);
Config::set('remote.connections.runtime.password', $target['password']);
#endsetup
#servers($connection)
#task('foo', ['on' => 'web'])
SSH::into('runtime')->run(array(
'docker stop ' . $server
));
#endtask
Command: envoy run foo --user=root --host=94.130.97.242 --password=password --server=22
After running it giive an error syntaxt error unexpected token'runtime'.
I need your help. Thank you!
Here is a way with a Symfony process (natively available within Laravel)
use Symfony\Component\Process\Process;
function start(string $user, string $host)
{
$sshSetting = sprintf('ssh://%s#%s', $user, $host);
$process = new Process([
'docker', '-H', $sshSetting, 'start'
]);
$process->run(); //synchronous
$process->mustRun(); //synchronous, throw an exception whenever fail
$process->start(); //asynchronous
}
Here is the official documentation https://symfony.com/doc/current/components/process.html#running-processes-asynchronously

storageclient class can't be found?

I'm trying desperately to figure out how to create a simple audio transcription script (for longer audio files) via PHP (the only language I know). I'm getting the error Class 'Google\Cloud\Storage\StorageClient' not found
I'm using the gcloud console code editor and everything should be installed (unless there is a separate composer install just for cloud storage, although I haven't been able to find anything about it in the documentation if there is).
I also entered gcloud auth application-default print-access-token which printed out an access token, but I don't know what (if any) I'm supposed to do with that other than the "set GOOGLE_APPLICATION_CREDENTIALS" command that I copied and pasted into the console shell prompt.
Here's the php code:
<?php
namespace Google\Cloud\Samples\Speech;
require __DIR__ . '/vendor/autoload.php';
use Exception;
# [START speech_transcribe_async_gcs]
use Google\Cloud\Speech\SpeechClient;
use Google\Cloud\Storage\StorageClient;
use Google\Cloud\Core\ExponentialBackoff;
$projectId = 'xxxx';
$speech = new SpeechClient([
'projectId' => $projectId,
'languageCode' => 'en-US',
]);
$filename = "20180925_184741_L.mp3";
# The audio file's encoding and sample rate
$options = [
'encoding' => 'LINEAR16',
'sampleRateHertz' => 16000,
'languageCode' => 'en-US',
'enableWordTimeOffsets' => false,
'enableAutomaticPunctuation' => true,
'model' => 'video',
];
function transcribe_async_gcs($bucketName, $objectName, $languageCode = 'en-US', $options = [])
{
// Create the speech client
$speech = new SpeechClient([
'languageCode' => $languageCode,
]);
// Fetch the storage object
$storage = new StorageClient();
$object = $storage->bucket($bucketName)->object($objectName);
// Create the asyncronous recognize operation
$operation = $speech->beginRecognizeOperation(
$object,
$options
);
// Wait for the operation to complete
$backoff = new ExponentialBackoff(10);
$backoff->execute(function () use ($operation) {
print('Waiting for operation to complete' . PHP_EOL);
$operation->reload();
if (!$operation->isComplete()) {
throw new Exception('Job has not yet completed', 500);
}
});
// Print the results
if ($operation->isComplete()) {
$results = $operation->results();
foreach ($results as $result) {
$alternative = $result->alternatives()[0];
printf('Transcript: %s' . PHP_EOL, $alternative['transcript']);
printf('Confidence: %s' . PHP_EOL, $alternative['confidence']);
}
}
}
# [END speech_transcribe_async_gcs]
transcribe_async_gcs("session_audio", $filename, "en-US", $options);
With apologies, PHP is not a language I'm proficient with but, I suspect you haven't (and must) install the client library for Cloud Storage so that your code may access it. This would explain its report that the Class is missing.
The PHP client library page includes two alternatives. One applies if you're using Composer, the second -- possibly what you want -- a direct download which you'll need to path correctly for your code.
Some time ago, I wrote a short blog post providing a simple example (using Cloud Storage) for each of Google's supported languages. Perhaps it will help you too.

ssh2_auth_pubkey_file authentication always fails

I'm trying to connect to another machine using PHP's ssh2 functions. I know the ssh keys have been created with no passwords and are distributed correctly, I can ssh user#host in the terminal on my machine to the server.
The PHP function tries to connect to a ip address using an ssh key file:-
function minnerConnect($miner_serial) {
$port = '7822';
$miner_ip = $this->getMinerIp($miner_serial);
$methods = array(
'kex' => 'diffie-hellman-group1-sha1',
'hostkey' => 'ssh-dss',
'client_to_server' => array(
'crypt' => '3des-cbc',
'mac' => 'hmac-md5',
'comp' => 'none'),
'server_to_client' => array(
'crypt' => '3des-cbc',
'mac' => 'hmac-md5',
'comp' => 'none'));
$connection = ssh2_connect($miner_ip, $port, $methods);
if (ssh2_auth_pubkey_file($connection, 'root',
'/root/.ssh/id_dsa.pub',
'/root/.ssh/id_dsa','')) {
echo "Public Key Authentication Successful\n";
} else {
echo "Public Key Authentication Failed";
}
but the error shown is:-
( ! ) Warning: ssh2_auth_pubkey_file(): Authentication failed for root using public key: Callback returned error in /var/www/application/models/miner_model.php on line 95
line 95 is '/root/.ssh/id_dsa','')) {.
Can anybody suggest a fix?
The error in this case was that the keys were generated by the root user, but they need to be accessible by the web server group/owner www-data.
I didn't like the idea of keeping ssh keys in a web folder open to www-data, so I moved the key files to a new user's home directory (/home/keyuser/) then made them accessible to www-data. Authentication was successful.
Even though the original error was saying it found the file, it couldn't read the file.
A better debug method is to try reading the file via php:
$prv_key = file_get_contents('/var/www/application/files/id_dsa');
print "<pre>";
var_export($prv_key);
print "</pre>";

Trigger ISPConfig vhost folders creation

I make an script that fill up all ISPConfig tables by itself and now i only need to raise some script to create the needed vhost and the rest of the symblink needed for apache to work.
My Script is working like a charm since i can view all the data correctly using the ISPConfig frontend.
Digging into the ISPConfig panel i see a RaiseEvent function triggered everytime a record is created but i can't trace where it ends and how it perform the creation of the symblink.
Maybe calling some function or cron it can work.
I'm using Apache 2 + PHP 5.3 + MySQL + ISPConfig 3 on Ubuntu Server 10.4
Ok I respond myself.
Since version 3 ISPConfig came with a simple API that let you performe some operation like Adding FTP Users, Websites and Databases.
I left here an example of how to create a database:
$params_db = array(
'server_id' => '1',
'system_user' => "web10",
'system_group' => 'client0',
'active' => 'y',
'type' => 'mysql',
'database_name' => $NAME,
'database_user' => $NAME,
'database_password' => '123456',
'database_charset' => 'utf8',
'remote_access' => 'n',
);
Next we have to create on the ISPConfig panel a "remote user" that allow to comunicate using the webservice.
$soap_username = 'whatever';
$soap_password = 'h4ck3m3';
$soap_location = 'http://localhost:8080/remote/index.php';
$soap_uri = 'http://localhost:8080/remote/';
$client = new SoapClient(null, array('location' => $soap_location, 'uri' => $soap_uri));
So, what's next?
Next we call the webserver function like this:
try
{
//* Login to the remote server
if( $session_id = $client->login($soap_username,$soap_password))
{
echo 'Logged into remote server sucessfully. The SessionID is '.$session_id. "\n";
$client->sites_database_add($session_id, $client_id, $params_db);
//* Logout
if($client->logout($session_id))
{
echo "DB Created\n";
}
}
}
catch (SoapFault $e)
{
die('SOAP Error: '.$e->getMessage());
}
For more information check out this link of howtogeek website: http://www.howtoforge.com/how-to-create-remote-api-scripts-for-ispconfig-3

Categories