PHP code example of artemyurov / laravel-autossh-tunnel

1. Go to this page and download the library: Download artemyurov/laravel-autossh-tunnel library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

artemyurov / laravel-autossh-tunnel example snippets


return [
    // Default tunnel name
    'default' => env('TUNNEL_CONNECTION', 'remote_db'),

    // Enable detailed logging
    'debug' => env('TUNNEL_DEBUG', env('APP_DEBUG', false)),

    // AutoSSH configuration
    'autossh' => [
        'enabled' => env('TUNNEL_AUTOSSH_ENABLED', true),
    ],

    // Retry configuration for database operations
    'retry' => [
        'max_attempts' => env('TUNNEL_RETRY_MAX_ATTEMPTS', 3),
        'delay' => env('TUNNEL_RETRY_DELAY', 2),
        'exponential' => env('TUNNEL_RETRY_EXPONENTIAL', false),
    ],

    // Connection validation settings
    'validation' => [
        'port_timeout' => env('TUNNEL_VALIDATION_PORT_TIMEOUT', 1),
        'database_timeout' => env('TUNNEL_VALIDATION_DATABASE_TIMEOUT', 5),
        'database_max_attempts' => env('TUNNEL_VALIDATION_DATABASE_MAX_ATTEMPTS', 5),
        'database_retry_delay' => env('TUNNEL_VALIDATION_DATABASE_RETRY_DELAY', 2),
    ],

    // Signal handling (SIGINT, SIGTERM)
    'signals' => [
        'enabled' => env('TUNNEL_SIGNALS_ENABLED', true),
        'handlers' => ['SIGINT', 'SIGTERM'],
    ],

    // Tunnel reuse settings
    'reuse' => [
        'use_pid_file' => env('TUNNEL_REUSE_PID_FILE', true),
        'use_port_scan' => env('TUNNEL_REUSE_PORT_SCAN', true),
        'pid_directory' => env('TUNNEL_PID_DIRECTORY', sys_get_temp_dir() . '/laravel-autossh-tunnel'),
    ],

    'connections' => [
        'remote_db' => [
            'type' => 'forward',
            // SSH Connection
            'user' => env('TUNNEL_SSH_USER'),
            'host' => env('TUNNEL_SSH_HOST'),
            'port' => env('TUNNEL_SSH_PORT', 22),
            'identity_file' => env('TUNNEL_SSH_KEY'),
            // Remote Target
            'remote_host' => env('TUNNEL_REMOTE_HOST', 'localhost'),
            'remote_port' => env('TUNNEL_REMOTE_PORT', 5432),
            // Local Bind
            'local_host' => env('TUNNEL_LOCAL_HOST', '127.0.0.1'),
            'local_port' => env('TUNNEL_LOCAL_PORT', 15432),
            // SSH Options (all optional, defaults shown)
            'ssh_options' => [
                'StrictHostKeyChecking' => env('TUNNEL_SSH_STRICT_HOST_KEY_CHECKING', false),
                'ServerAliveInterval' => env('TUNNEL_SSH_SERVER_ALIVE_INTERVAL', 60),
                'ServerAliveCountMax' => env('TUNNEL_SSH_SERVER_ALIVE_COUNT_MAX', 3),
                'ExitOnForwardFailure' => env('TUNNEL_SSH_EXIT_ON_FORWARD_FAILURE', true),
                'TCPKeepAlive' => env('TUNNEL_SSH_TCP_KEEP_ALIVE', true),
                'ConnectTimeout' => env('TUNNEL_SSH_CONNECT_TIMEOUT', 10),
            ],
        ],

        'local_webhooks' => [
            'type' => 'reverse',
            'user' => env('WEBHOOK_SSH_USER'),
            'host' => env('WEBHOOK_SSH_HOST'),
            'port' => env('WEBHOOK_SSH_PORT', 22),
            'identity_file' => env('WEBHOOK_SSH_KEY'),
            'remote_host' => env('WEBHOOK_REMOTE_HOST', 'localhost'),  // Or 0.0.0.0 for public access
            'remote_port' => env('WEBHOOK_REMOTE_PORT', 8080),
            'local_host' => env('WEBHOOK_LOCAL_HOST', '127.0.0.1'),
            'local_port' => env('WEBHOOK_LOCAL_PORT', 8000),
            'ssh_options' => [
                'StrictHostKeyChecking' => env('WEBHOOK_SSH_STRICT_HOST_KEY_CHECKING', false),
                'ServerAliveInterval' => env('WEBHOOK_SSH_SERVER_ALIVE_INTERVAL', 60),
                'ServerAliveCountMax' => env('WEBHOOK_SSH_SERVER_ALIVE_COUNT_MAX', 3),
                'ExitOnForwardFailure' => env('WEBHOOK_SSH_EXIT_ON_FORWARD_FAILURE', true),
                'TCPKeepAlive' => env('WEBHOOK_SSH_TCP_KEEP_ALIVE', true),
                'ConnectTimeout' => env('WEBHOOK_SSH_CONNECT_TIMEOUT', 10),
            ],
        ],
    ],
];

// config/tunnel.php
'connections' => [
    'remote_dev_db' => [
        'type' => 'forward',
        'user' => env('REMOTE_DEV_SSH_USER'),
        'host' => env('REMOTE_DEV_SSH_HOST'),
        'port' => env('REMOTE_DEV_SSH_PORT', 22),
        'identity_file' => env('REMOTE_DEV_SSH_KEY'),
        'remote_host' => env('REMOTE_DEV_REMOTE_HOST', 'localhost'),
        'remote_port' => env('REMOTE_DEV_REMOTE_PORT', 5432),
        'local_host' => env('REMOTE_DEV_LOCAL_HOST', '127.0.0.1'),
        'local_port' => env('REMOTE_DEV_LOCAL_PORT', 16432),
    ],

    'legacy_db' => [
        'type' => 'forward',
        'user' => env('LEGACY_SSH_USER'),
        'host' => env('LEGACY_SSH_HOST'),
        'port' => env('LEGACY_SSH_PORT', 22),
        'identity_file' => env('LEGACY_SSH_KEY'),
        'remote_host' => env('LEGACY_REMOTE_HOST', '127.0.0.1'),
        'remote_port' => env('LEGACY_REMOTE_PORT', 3306),
        'local_host' => env('LEGACY_LOCAL_HOST', '127.0.0.1'),
        'local_port' => env('LEGACY_LOCAL_PORT', 13306),
    ],
],

use ArtemYurov\Autossh\Facades\Tunnel;

// Access remote database
Tunnel::connection('remote_db')->execute(function() {
    // Connect to remote PostgreSQL via localhost:15432
    $users = DB::connection('pgsql_remote')->table('users')->get();
});

use ArtemYurov\Autossh\Facades\Tunnel;

// Expose local Laravel app for webhook testing
Tunnel::connection('local_webhooks')->execute(function() {
    $this->info('Local app is now accessible at http://your-server.com:8080');
    $this->info('Configure webhooks to point to this URL');

    // Keep tunnel open while testing
    sleep(3600); // 1 hour
});

use ArtemYurov\Autossh\Facades\Tunnel;

// Using configuration from config/tunnel.php
Tunnel::connection('remote_db')->execute(function() {
    // Tunnel is active, you can work with remote service
    // Tunnel will automatically close after execution
});

use ArtemYurov\Autossh\Facades\Tunnel;
use Illuminate\Support\Facades\DB;

Tunnel::connection('remote_db')
    ->withDatabaseConnection('pgsql_remote', [
        'driver' => 'pgsql',
        'database' => env('REMOTE_DB_DATABASE'),
        'username' => env('REMOTE_DB_USERNAME'),
        'password' => env('REMOTE_DB_PASSWORD'),
    ])
    ->execute(function() {
        // Now you can use the connection
        $users = DB::connection('pgsql_remote')->table('users')->get();

        // Tunnel will automatically close after execution
    });

use ArtemYurov\Autossh\Facades\Tunnel;

$connection = Tunnel::connection('remote_db')->start();

try {
    // Work with tunnel
    $pid = $connection->getPid();
    $isRunning = $connection->isRunning();
} finally {
    // Must close the tunnel
    $connection->stop();
}

use ArtemYurov\Autossh\Tunnel;

// PostgreSQL tunnel
$pgTunnel = Tunnel::connection('pgsql')->start();

// MySQL tunnel
$mysqlTunnel = Tunnel::connection('mysql')->start();

try {
    // Work with both tunnels
} finally {
    $pgTunnel->stop();
    $mysqlTunnel->stop();
}

namespace App\Console\Commands;

use Illuminate\Console\Command;
use ArtemYurov\Autossh\Facades\Tunnel;
use Illuminate\Support\Facades\DB;

class SyncDatabase extends Command
{
    protected $signature = 'db:sync';

    public function handle(): int
    {
        return Tunnel::connection('remote_db')
            ->withDatabaseConnection('remote_db', [
                'driver' => 'pgsql',
                'database' => env('REMOTE_DB_DATABASE'),
                'username' => env('REMOTE_DB_USERNAME'),
                'password' => env('REMOTE_DB_PASSWORD'),
            ])
            ->execute(function() {
                $this->info('Syncing database...');

                // Your sync logic
                $tables = DB::connection('remote_db')
                    ->select("SELECT tablename FROM pg_tables WHERE schemaname = 'public'");

                $this->info('Found tables: ' . count($tables));

                return Command::SUCCESS;
            });
    }
}

use ArtemYurov\Autossh\Facades\Tunnel;
use ArtemYurov\Autossh\Exceptions\TunnelConnectionException;
use ArtemYurov\Autossh\Exceptions\TunnelConfigException;

try {
    Tunnel::connection('remote_db')->execute(function() {
        // Your code
    });
} catch (TunnelConfigException $e) {
    // Configuration error (invalid port, missing key, etc.)
    Log::error('Tunnel configuration error: ' . $e->getMessage());
} catch (TunnelConnectionException $e) {
    // Connection error (port occupied, SSH failed, etc.)
    Log::error('Tunnel connection error: ' . $e->getMessage());
}

// ❌ WRONG - Will attempt Unix socket, not tunnel
Tunnel::connection('mysql_tunnel')
    ->withDatabaseConnection('mysql_remote', [
        'driver' => 'mysql',
        'host' => 'localhost',  // ❌ Unix socket
        'port' => 13306,
    ]);

// ✅ CORRECT - Will use TCP/IP through tunnel
Tunnel::connection('mysql_tunnel')
    ->withDatabaseConnection('mysql_remote', [
        'driver' => 'mysql',
        'host' => '127.0.0.1',  // ✅ TCP/IP
        'port' => 13306,
    ]);

// config/tunnel.php
'mysql_remote' => [
    'type' => 'forward',
    'user' => env('MYSQL_SSH_USER'),
    'host' => env('MYSQL_SSH_HOST'),
    'port' => env('MYSQL_SSH_PORT', 22),

    // ✅ IMPORTANT: Use 127.0.0.1 for MySQL/MariaDB
    'remote_host' => env('MYSQL_REMOTE_HOST', '127.0.0.1'),
    'remote_port' => env('MYSQL_REMOTE_PORT', 3306),
    'local_host' => env('MYSQL_LOCAL_HOST', '127.0.0.1'),
    'local_port' => env('MYSQL_LOCAL_PORT', 13306),
],

use ArtemYurov\Autossh\Tunnel;

// Automatically reuse existing tunnel or create new one
$tunnel = Tunnel::connection('remote_db')->reuseOrCreate();

// Or explicitly find existing tunnel by port
$pid = $tunnel->findExistingByPort();
if ($pid) {
    echo "Found existing tunnel with PID: $pid";
}

use ArtemYurov\Autossh\Tunnel;

$tunnel = Tunnel::connection('remote_db')
    ->withDatabaseConnection('pgsql_remote', [...])
    ->start();

// Execute with automatic retry on connection loss
$result = $tunnel->executeWithRetry(function() {
    return DB::connection('pgsql_remote')->table('users')->count();
}, $maxAttempts = 3);

'retry' => [
    'max_attempts' => 3,           // Maximum retry attempts
    'delay' => 2,                  // Delay between retries (seconds)
    'exponential' => false,        // Use exponential backoff (2s, 4s, 8s...)
],

use ArtemYurov\Autossh\Tunnel;

$connection = Tunnel::connection('remote_db')
    ->withDatabaseConnection('pgsql_remote', [...])
    ->start();

// Simple validation (SELECT 1 query)
if ($connection->validateDatabase('pgsql_remote')) {
    echo "Database is accessible";
}

// Wait for database with retries
if ($connection->waitForDatabase('pgsql_remote', $maxAttempts = 5, $delaySeconds = 2)) {
    echo "Database became available";
}

// Full tunnel validation (process + port + database)
$result = $connection->validate('pgsql_remote');
if ($result['valid']) {
    echo "Tunnel is fully operational";
} else {
    foreach ($result['errors'] as $error) {
        echo "Error: $error\n";
    }
}

use ArtemYurov\Autossh\Tunnel;

$connection = Tunnel::connection('remote_db')
    ->start()
    ->setupSignalHandlers();  // Handle SIGINT, SIGTERM

// Tunnel will be properly closed when receiving Ctrl+C or kill signal

'signals' => [
    'enabled' => true,
    'handlers' => ['SIGINT', 'SIGTERM'],
],

use ArtemYurov\Autossh\Tunnel;

$connection = Tunnel::connection('remote_db')
    ->start()
    ->withKeepAlive(true);

// Tunnel will stay alive even after script finishes
echo "Tunnel PID: " . $connection->getPid();

namespace App\Console\Commands;

use Illuminate\Console\Command;
use ArtemYurov\Autossh\Console\Traits\ManagesTunnel;
use Illuminate\Support\Facades\DB;

class SyncRemoteData extends Command
{
    use ManagesTunnel;

    protected $signature = 'data:sync';

    public function handle(): int
    {
        // Setup tunnel with automatic reconnection and validation
        $this->setupTunnel('remote_db', [
            'connection_name' => 'pgsql_remote',
            'driver' => 'pgsql',
            'database' => env('REMOTE_DB_DATABASE'),
            'username' => env('REMOTE_DB_USERNAME'),
            'password' => env('REMOTE_DB_PASSWORD'),
        ], $keepAlive = false, $validateDb = true);

        try {
            // Execute with automatic retry on connection errors
            $this->withTunnelRetry(function() {
                $data = DB::connection('pgsql_remote')
                    ->table('users')
                    ->get();

                $this->info("Synced " . count($data) . " records");
            });

            return Command::SUCCESS;

        } finally {
            // Graceful tunnel closure
            $this->closeTunnel();
        }
    }
}

'debug' => true,
bash
php artisan tunnel:start
# or specify connection
php artisan tunnel:start remote_db
bash
php artisan tunnel:start --detach
# or
php artisan tunnel:start remote_db --detach
bash
php artisan tunnel:stop
php artisan tunnel:stop remote_db

# Stop all tunnels
php artisan tunnel:stop --all
bash
# Find and reuse existing tunnel
php artisan tunnel:reuse remote_db

# Reuse tunnel and register database connection
php artisan tunnel:reuse remote_db \
    --db-connection=pgsql_remote \
    --db-database=mydb \
    --db-username=user \
    --db-password=pass
bash
php artisan tunnel:stop remote_db
bash
# Basic diagnostics
php artisan tunnel:diagnose remote_db

# Include database check
php artisan tunnel:diagnose remote_db --db-connection=pgsql_remote

# Verbose output
php artisan tunnel:diagnose remote_db --verbose