Skip to main content
Glama

ubuntu_ssl_certificate

Manage Let's Encrypt SSL certificates on Ubuntu servers via SSH. Issue, renew, check status, or list certificates for specified domains with optional webroot path and sudo access.

Instructions

Manage SSL certificates using Let's Encrypt on Ubuntu

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction to perform (issue, renew, status, list)
connectionIdYesID of an active SSH connection
domainNoDomain name for the certificate (required for issue and renew)
emailNoEmail address for Let's Encrypt notifications (required for issue)
sudoNoWhether to run the command with sudo (default: true)
webrootNoWeb root path for domain verification (default: /var/www/html)

Implementation Reference

  • The main handler function implementing the ubuntu_ssl_certificate tool logic, handling actions like issue, renew, status, list using certbot over SSH.
    async ubuntu_ssl_certificate(params) { const { connectionId, action, domain, email, webroot = '/var/www/html', sudo = true } = params; try { const conn = getConnection(connectionMap, connectionId); const sudoPrefix = sudo ? 'sudo ' : ''; // Validate action const validActions = ['issue', 'renew', 'status', 'list']; if (!validActions.includes(action)) { throw new Error(`Invalid action: ${action}. Valid actions are: ${validActions.join(', ')}`); } // Check for required parameters if ((action === 'issue' || action === 'renew') && !domain) { throw new Error(`Domain name is required for ${action} action`); } if (action === 'issue' && !email) { throw new Error('Email address is required for issue action'); } // Ensure certbot is installed const checkCertbot = await executeSSHCommand(conn, 'which certbot || echo "not-found"'); if (checkCertbot.stdout === 'not-found') { const installCertbot = await executeSSHCommand( conn, `${sudoPrefix}apt-get update && ${sudoPrefix}apt-get install -y certbot python3-certbot-nginx` ); if (installCertbot.code !== 0) { throw new Error(`Failed to install certbot: ${installCertbot.stderr}`); } } let command = ''; switch (action) { case 'issue': command = `${sudoPrefix}certbot certonly --webroot -w ${webroot} -d ${domain} --email ${email} --agree-tos --non-interactive`; break; case 'renew': command = domain ? `${sudoPrefix}certbot renew --cert-name ${domain} --force-renewal` : `${sudoPrefix}certbot renew`; break; case 'status': command = domain ? `${sudoPrefix}certbot certificates -d ${domain}` : `${sudoPrefix}certbot certificates`; break; case 'list': command = `${sudoPrefix}certbot certificates`; break; } const result = await executeSSHCommand(conn, command); return { content: [{ type: 'text', text: `SSL certificate ${action} result:\n\n${result.stdout || result.stderr}` }] }; } catch (error: any) { return { content: [{ type: 'text', text: `SSL certificate error: ${error.message}` }], isError: true }; } },
  • The input schema and description for the ubuntu_ssl_certificate tool.
    ubuntu_ssl_certificate: { description: 'Manage SSL certificates using Let\'s Encrypt on Ubuntu', inputSchema: { type: 'object', properties: { connectionId: { type: 'string', description: 'ID of an active SSH connection' }, action: { type: 'string', description: 'Action to perform (issue, renew, status, list)' }, domain: { type: 'string', description: 'Domain name for the certificate (required for issue and renew)' }, email: { type: 'string', description: 'Email address for Let\'s Encrypt notifications (required for issue)' }, webroot: { type: 'string', description: 'Web root path for domain verification (default: /var/www/html)' }, sudo: { type: 'boolean', description: 'Whether to run the command with sudo (default: true)' } }, required: ['connectionId', 'action'] } },
  • src/index.ts:293-296 (registration)
    Registration of ubuntu tools (including ubuntu_ssl_certificate) in the main CallToolRequestSchema handler by dispatching to ubuntuToolHandlers.
    // Handle Ubuntu tools directly if (toolName.startsWith('ubuntu_') && ubuntuToolHandlers[toolName]) { return ubuntuToolHandlers[toolName](request.params.arguments); }
  • Utility helper function executeSSHCommand used by the handler to run SSH commands.
    // Utility function to execute commands with error handling async function executeSSHCommand(conn: Client, command: string, timeout = 60000): Promise<{ code: number; signal: string; stdout: string; stderr: string; }> { return new Promise((resolve, reject) => { // Set up timeout const timeoutId = setTimeout(() => { reject(new Error(`Command execution timed out after ${timeout}ms`)); }, timeout); conn.exec(command, {}, (err: Error | undefined, stream: any) => { if (err) { clearTimeout(timeoutId); return reject(new Error(`Failed to execute command: ${err.message}`)); } let stdout = ''; let stderr = ''; stream.on('close', (code: number, signal: string) => { clearTimeout(timeoutId); resolve({ code, signal, stdout: stdout.trim(), stderr: stderr.trim() }); }); stream.on('data', (data: Buffer) => { stdout += data.toString(); }); stream.stderr.on('data', (data: Buffer) => { stderr += data.toString(); }); }); }); }
  • Helper function getConnection to retrieve active SSH connection.
    // Helper function to check if a connection exists function getConnection(connections: Map<string, { conn: Client; config: any }>, connectionId: string) { if (!connections.has(connectionId)) { throw new Error(`No active SSH connection with ID: ${connectionId}`); } return connections.get(connectionId)!.conn; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mixelpixx/SSH-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server