<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: AlpacaX</title>
    <description>The latest articles on DEV Community by AlpacaX (@alpacax).</description>
    <link>https://dev.to/alpacax</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3480620%2F7377ab1e-a0a8-4bff-9951-a53c1a18f812.png</url>
      <title>DEV Community: AlpacaX</title>
      <link>https://dev.to/alpacax</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alpacax"/>
    <language>en</language>
    <item>
      <title>Work sessions reach the CLI: making bash scripts session-aware</title>
      <dc:creator>AlpacaX</dc:creator>
      <pubDate>Mon, 01 Jun 2026 16:30:00 +0000</pubDate>
      <link>https://dev.to/alpacax/work-sessions-reach-the-cli-making-bash-scripts-session-aware-5522</link>
      <guid>https://dev.to/alpacax/work-sessions-reach-the-cli-making-bash-scripts-session-aware-5522</guid>
      <description>&lt;p&gt;Your bash script doesn't know it's a privileged session. Your runbook doesn't either. Here's what changes when the CLI itself becomes session-aware.&lt;/p&gt;

&lt;p&gt;If you've ever run a production change from a terminal, you've probably written something like this at the top of a remediation script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# Production change: ticket INC-2384&lt;/span&gt;
&lt;span class="c"&gt;# Approved verbally in #incidents by @oncall-lead&lt;/span&gt;
&lt;span class="c"&gt;# Scope: restart auth-svc on prod-api-{01..04}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That comment is the closest thing to "declared intent" that most shops have. The audit log captures every command the script runs, but it doesn't know &lt;em&gt;why&lt;/em&gt; you ran them, who approved them, or where the change starts and stops. When the auditor asks "show me what changed in production last Thursday," you stitch four log sources together the night before the review.&lt;/p&gt;

&lt;p&gt;Alpacon's W19 release made the &lt;strong&gt;work session&lt;/strong&gt; a first-class object across the server, web console, and agent—a single named container with declared purpose, an approval gate, a unified timeline, and a post-session summary. The remaining gap was the CLI: the surface where SREs, runbooks, and automation actually live.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;alpacon-cli v1.4.6&lt;/code&gt;, that gap closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What shipped
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;alpacon-cli v1.4.6&lt;/code&gt; adds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A top-level &lt;code&gt;work-session&lt;/code&gt; command tree (&lt;a href="https://github.com/alpacax/alpacon-cli/pull/165" rel="noopener noreferrer"&gt;PR 165&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;--work-session&lt;/code&gt; flag on &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;websh&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt;, and &lt;code&gt;tunnel&lt;/code&gt;, plus &lt;code&gt;work-session use&lt;/code&gt; to set the active session for the current workspace (&lt;a href="https://github.com/alpacax/alpacon-cli/pull/167" rel="noopener noreferrer"&gt;PR 167&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;work-session approve&lt;/code&gt;, &lt;code&gt;reject&lt;/code&gt;, and &lt;code&gt;revoke&lt;/code&gt; subcommands (&lt;a href="https://github.com/alpacax/alpacon-cli/pull/171" rel="noopener noreferrer"&gt;PR 171&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;alpacon-web 1.3.15&lt;/code&gt; adds the matching server-side knob: a sudo policy setting that lets operators say "inside an approved work session, skip MFA on sudo" (&lt;a href="https://github.com/alpacax/alpacon-web/pull/1150" rel="noopener noreferrer"&gt;PR 1150&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;If you've read the &lt;a href="https://www.alpacax.com/newsroom/archive/work-sessions-the-audit-unit-your-ciso-needs/" rel="noopener noreferrer"&gt;W19 work-session blog post&lt;/a&gt;, the model is the same—declared intent, approval gate, session-scoped sudo, unified timeline, AI summary. This piece is about reaching that model from the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CLI flow
&lt;/h2&gt;

&lt;p&gt;Here's an SRE responding to a paging alert on a 200-server fleet. The runbook needs to restart &lt;code&gt;auth-svc&lt;/code&gt; on four hosts. Before today, this was a bash one-liner with a comment block. Now it's a session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Open the session with declared purpose.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;alpacon work-session create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--purpose&lt;/span&gt; &lt;span class="s2"&gt;"INC-2384: restart auth-svc on prod-api-01..04"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scope&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--server&lt;/span&gt; prod-api-01,prod-api-02,prod-api-03,prod-api-04 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expires-in&lt;/span&gt; 2h &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The session is created in a pending state with the purpose recorded as a first-class field. &lt;code&gt;--scope&lt;/code&gt; declares the access types you need (&lt;code&gt;command&lt;/code&gt;, &lt;code&gt;websh&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;tunnel&lt;/code&gt;); &lt;code&gt;--server&lt;/code&gt; names the targets; &lt;code&gt;--expires-in&lt;/code&gt; (or &lt;code&gt;--expires-at&lt;/code&gt; for an absolute RFC3339 timestamp) bounds the window. &lt;code&gt;--wait&lt;/code&gt; polls every 10 seconds for up to 30 attempts and returns when the session is approved or rejected, so the requester's terminal blocks here instead of context-switching.&lt;/p&gt;

&lt;p&gt;No "approved verbally in #incidents"—the declared intent is the artifact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The approver reviews and approves.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the realistic on-call flow, the approver is a second engineer on the bridge. They can approve from the web console (where the work-sessions list page now has a filter bar—&lt;a href="https://github.com/alpacax/alpacon-web/pull/1150" rel="noopener noreferrer"&gt;PR 1150&lt;/a&gt;) or from their own CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;alpacon work-session approve &amp;lt;session-id&amp;gt;

&lt;span class="c"&gt;# Optionally narrow scope or targets at approval time:&lt;/span&gt;
alpacon work-session approve &amp;lt;session-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scope&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--server&lt;/span&gt; prod-api-01,prod-api-02
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;reject &amp;lt;session-id&amp;gt;&lt;/code&gt; and &lt;code&gt;revoke &amp;lt;session-id&amp;gt;&lt;/code&gt; are the parallel verbs—reject before activation, revoke to force-terminate an approved or active session. All three are superuser-only and the permission check is enforced server-side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Activate the session, pin it for this workspace, then run the change.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;alpacon work-session activate &amp;lt;session-id&amp;gt;
alpacon work-session use &amp;lt;session-id&amp;gt;

alpacon &lt;span class="nb"&gt;exec &lt;/span&gt;prod-api-01 &lt;span class="nt"&gt;--&lt;/span&gt; systemctl restart auth-svc
alpacon &lt;span class="nb"&gt;exec &lt;/span&gt;prod-api-02 &lt;span class="nt"&gt;--&lt;/span&gt; systemctl restart auth-svc
alpacon &lt;span class="nb"&gt;exec &lt;/span&gt;prod-api-03 &lt;span class="nt"&gt;--&lt;/span&gt; systemctl restart auth-svc
alpacon &lt;span class="nb"&gt;exec &lt;/span&gt;prod-api-04 &lt;span class="nt"&gt;--&lt;/span&gt; systemctl restart auth-svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;activate&lt;/code&gt; flips the session from approved to active. &lt;code&gt;use&lt;/code&gt; writes the active session ID into &lt;code&gt;~/.alpacon/config.json&lt;/code&gt; for the current workspace, so every subsequent &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;websh&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt;, and &lt;code&gt;tunnel&lt;/code&gt; call attaches the session automatically. Each tagged call prints &lt;code&gt;Using work-session &amp;lt;uuid&amp;gt;&lt;/code&gt; to stderr so &lt;code&gt;--output json&lt;/code&gt; pipelines stay clean.&lt;/p&gt;

&lt;p&gt;Three ways to attach a session, in resolution order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Inline flag — overrides everything else, single invocation&lt;/span&gt;
alpacon &lt;span class="nb"&gt;cp&lt;/span&gt; ./hotfix.tar.gz prod-api-01:/tmp/ &lt;span class="nt"&gt;--work-session&lt;/span&gt; &amp;lt;session-id&amp;gt;

&lt;span class="c"&gt;# 2. Env var — shell-scoped, overrides workspace config, ideal for CI runners&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ALPACON_WORK_SESSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;session-id&amp;gt;
alpacon &lt;span class="nb"&gt;exec &lt;/span&gt;prod-api-01 &lt;span class="nt"&gt;--&lt;/span&gt; systemctl restart auth-svc

&lt;span class="c"&gt;# 3. Workspace config via 'work-session use' — sticks until you unset it&lt;/span&gt;
alpacon work-session use &amp;lt;session-id&amp;gt;
&lt;span class="c"&gt;# To clear:&lt;/span&gt;
alpacon work-session use &lt;span class="nt"&gt;--unset&lt;/span&gt;
&lt;span class="c"&gt;# To inspect:&lt;/span&gt;
alpacon work-session current
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resolution priority: &lt;code&gt;--work-session&lt;/code&gt; flag &amp;gt; &lt;code&gt;ALPACON_WORK_SESSION&lt;/code&gt; env var &amp;gt; workspace config &amp;gt; no session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Complete the session when the change is done.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;alpacon work-session &lt;span class="nb"&gt;complete&lt;/span&gt; &amp;lt;session-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The session ends, the in-session policy stops applying, and the unified timeline is now exportable as a single audit artifact—the same one the W19 blog post described for human shell sessions, but driven entirely from a terminal. If you need more time mid-flight, &lt;code&gt;alpacon work-session extend &amp;lt;session-id&amp;gt; --expires-in 1h&lt;/code&gt; pushes the expiry back.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MFA-bypass policy
&lt;/h2&gt;

&lt;p&gt;The matching &lt;code&gt;alpacon-web 1.3.15&lt;/code&gt; setting deserves its own paragraph because it's the operator-facing knob that makes session-scoped intent practical for automation.&lt;/p&gt;

&lt;p&gt;Per-command MFA prompts are the right default for ad-hoc privileged work. They are not the right default inside an approved session where the purpose, scope, and approver are already on file—automation will get blocked, on-call engineers will start working around the prompts, and you'll end up with a worse audit trail, not a better one.&lt;/p&gt;

&lt;p&gt;The new sudo policy setting (&lt;a href="https://github.com/alpacax/alpacon-web/pull/1150" rel="noopener noreferrer"&gt;PR 1150&lt;/a&gt;) lets a workspace admin say: "inside a work session that's been approved for this scope, the declared purpose and approver substitute for a per-command MFA prompt." Outside that session, MFA still fires. The governance signal moves up a level—from "did this command prompt MFA?" to "did this session have declared intent and an approver?"—without losing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this completes
&lt;/h2&gt;

&lt;p&gt;Session-scoped intent is one of the moat pillars Alpacon has been building toward all year. With this release, it's end-to-end across &lt;strong&gt;server → console → agent → CLI&lt;/strong&gt;. The CLI was the last surface where session governance was bypassable; a script could &lt;code&gt;alpacon exec&lt;/code&gt; its way through a privileged change and the audit log would capture the commands but not the session boundary. That gap is now closed.&lt;/p&gt;

&lt;p&gt;For an SRE running automated remediation, this is the difference between "we have audit logs" and "we have an audit unit." The session is the artifact your auditor asks for—declared purpose, approver, timeline, summary, scope—and your runbook produces it as a side effect of doing the work.&lt;/p&gt;

&lt;p&gt;For a CISO in a SOC 2 or HIPAA cycle, the question shifts from "can you reconstruct what happened?" to "show me the session." One screen, one URL, exportable. Including the ones that ran from a terminal.&lt;/p&gt;

&lt;p&gt;If you want the longer "why session-scoped intent is the moat" argument, the W19 post is the canonical reference: &lt;a href="https://www.alpacax.com/newsroom/archive/work-sessions-the-audit-unit-your-ciso-needs/" rel="noopener noreferrer"&gt;the W19 work-sessions post&lt;/a&gt;. If you want to try the CLI flow, &lt;code&gt;alpacon-cli v1.4.6&lt;/code&gt; is on GitHub (&lt;a href="https://github.com/alpacax/alpacon-cli/releases/tag/v1.4.6" rel="noopener noreferrer"&gt;release notes&lt;/a&gt;) and the docs are at &lt;a href="https://docs.alpacax.com" rel="noopener noreferrer"&gt;docs.alpacax.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>security</category>
      <category>cli</category>
    </item>
    <item>
      <title>Stop Using SSH Keys in GitHub Actions (Here's What to Use Instead)</title>
      <dc:creator>AlpacaX</dc:creator>
      <pubDate>Sat, 11 Oct 2025 00:45:52 +0000</pubDate>
      <link>https://dev.to/alpacax/stop-using-ssh-keys-in-github-actions-heres-what-to-use-instead-1mbe</link>
      <guid>https://dev.to/alpacax/stop-using-ssh-keys-in-github-actions-heres-what-to-use-instead-1mbe</guid>
      <description>&lt;h1&gt;
  
  
  How We Fixed SSH in GitHub Actions (Real Use Cases)
&lt;/h1&gt;

&lt;h2&gt;
  
  
  The Problem: SSH in CI/CD Workflows
&lt;/h2&gt;

&lt;p&gt;If you're using GitHub Actions to deploy to your servers, you're probably doing something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Execute remote SSH commands&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;ssh-action&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.HOST }}&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.USERNAME }}&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SSH_PRIVATE_KEY }}&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.PORT }}&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;cd /app&lt;/span&gt;
      &lt;span class="s"&gt;git pull&lt;/span&gt;
      &lt;span class="s"&gt;npm install&lt;/span&gt;
      &lt;span class="s"&gt;pm2 restart app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach has worked for years, but it brings significant security and operational challenges that get worse as your infrastructure grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Risks
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Port 22 Exposed to the Internet&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every server with SSH enabled is under constant attack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bots scan for open port 22 thousands of times per day&lt;/li&gt;
&lt;li&gt;Automated brute force attempts against your SSH daemon&lt;/li&gt;
&lt;li&gt;Zero-day vulnerabilities in SSH daemon itself become attack vectors&lt;/li&gt;
&lt;li&gt;Even with fail2ban and strict firewall rules, the attack surface exists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check your auth logs, you'll see hundreds of failed login attempts from random IPs. That's the reality of exposing SSH to the internet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full Server Access with SSH Keys&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SSH keys are all-or-nothing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grant complete access to the server, no way to restrict which commands can be executed&lt;/li&gt;
&lt;li&gt;Read-only operations require the same access level as destructive ones&lt;/li&gt;
&lt;li&gt;If a key leaks (committed to git, logged, stolen laptop), attackers have full control&lt;/li&gt;
&lt;li&gt;No built-in mechanism to limit what GitHub Actions workflows can do&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SSH Keys Scattered Across GitHub Secrets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Managing SSH keys at scale becomes exponential pain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One SSH key per server: 10 servers = 10 different keys to track&lt;/li&gt;
&lt;li&gt;Each repository needs its own copy of these secrets&lt;/li&gt;
&lt;li&gt;No centralized view of which keys have access to which servers&lt;/li&gt;
&lt;li&gt;Organizational secrets help, but you're still managing one key per server&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Operational Pain Points
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Key Rotation is a Nightmare&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you need to rotate SSH keys (security incident, compliance requirement, or just good practice):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate new key pairs for each server&lt;/li&gt;
&lt;li&gt;Update &lt;code&gt;authorized_keys&lt;/code&gt; on every server&lt;/li&gt;
&lt;li&gt;Update GitHub Secrets in every repository that deploys to those servers&lt;/li&gt;
&lt;li&gt;Hope you didn't miss anything&lt;/li&gt;
&lt;li&gt;Deal with broken deployments when you inevitably did&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a team with 10 servers and 20 repositories, this is &lt;strong&gt;hours&lt;/strong&gt; of work that nobody wants to do. So keys don't get rotated as often as they should.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Centralized Audit Trail&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When something goes wrong in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logs are scattered across multiple servers&lt;/li&gt;
&lt;li&gt;SSH logs show IP addresses (GitHub Actions runners), not which repo/workflow ran what&lt;/li&gt;
&lt;li&gt;Manual investigation required: "Who deployed to prod last Tuesday at 3pm?"&lt;/li&gt;
&lt;li&gt;No easy way to trace which workflow executed which commands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You end up cross-referencing GitHub Actions logs, SSH auth logs, bash history, and application logs across multiple servers. It's tedious and error-prone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Per-Repository Secret Management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The same SSH keys get duplicated across repositories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update one key → Update it in dozens of places&lt;/li&gt;
&lt;li&gt;Revoking access means touching multiple repositories&lt;/li&gt;
&lt;li&gt;No fine-grained control over what each repository can do&lt;/li&gt;
&lt;li&gt;Junior developer's first deploy has the same access as senior engineer's emergency fix&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Real Cost
&lt;/h3&gt;

&lt;p&gt;These aren't just theoretical concerns. Here's what actually happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security incidents&lt;/strong&gt;: Leaked SSH keys in git history require emergency rotation across all servers and repos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken deployments&lt;/strong&gt;: Missed secret updates during key rotation cause failed releases at 2am&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance failures&lt;/strong&gt;: Auditors ask "Who ran this command?" and you can't easily answer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational overhead&lt;/strong&gt;: DevOps teams spend hours managing SSH keys instead of building features&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security compromise&lt;/strong&gt;: Keys don't get rotated because it's too painful, increasing risk over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the worst part? &lt;strong&gt;This scales badly&lt;/strong&gt;. Double your servers, and you double your key management burden.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Alpacon
&lt;/h2&gt;

&lt;p&gt;Alpacon replaces SSH with API tokens and provides four purpose-built GitHub Actions. Here's what changes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH keys → API tokens&lt;/li&gt;
&lt;li&gt;Port 22 exposure → Outbound connection (zero open ports)&lt;/li&gt;
&lt;li&gt;Full access → Command-level ACLs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What you gain:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Command ACL (Access Control Lists)&lt;/strong&gt;: Tokens only run commands you explicitly allow, even if leaked, only permitted commands work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workspace-level token&lt;/strong&gt;: One token manages &lt;strong&gt;multiple servers&lt;/strong&gt; at once&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic audit trail&lt;/strong&gt;: Know exactly which repo/workflow accessed which server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible token management&lt;/strong&gt;: Update token permissions or rotate without touching GitHub Secrets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero open ports&lt;/strong&gt;: Outbound connection, servers never listen for incoming connections&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How It Works in Detail
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Command ACL
&lt;/h3&gt;

&lt;p&gt;Unlike SSH keys (which give full access), Alpacon tokens support fine-grained command ACLs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00vefwhf36r8fqgq85y2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00vefwhf36r8fqgq85y2.png" alt=" " width="800" height="153"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works:&lt;/strong&gt;&lt;br&gt;
When creating a token, you specify exactly which commands it can execute. Commands with operators (&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;;&lt;/code&gt;) are blocked. This prevents command chaining or shell injection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prevention benefits:&lt;/strong&gt;&lt;br&gt;
Even if the token leaks, attackers cannot execute unauthorized commands. The token can ONLY run commands you explicitly allowed.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Zero Exposed Ports (Outbound Connection)
&lt;/h3&gt;

&lt;p&gt;Alpacon uses a &lt;strong&gt;outbound connection&lt;/strong&gt; model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your server initiates an &lt;strong&gt;outbound&lt;/strong&gt; connection to your workspace&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No inbound ports&lt;/strong&gt; opened on your server&lt;/li&gt;
&lt;li&gt;Server is &lt;strong&gt;not discoverable&lt;/strong&gt; from the internet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Threats eliminated:&lt;/strong&gt; SSH port scanning, brute force attacks, direct connection attempts.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Centralized Audit Trail
&lt;/h3&gt;

&lt;p&gt;All GitHub Actions activity is automatically tracked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Operator (user/token) and target server&lt;/li&gt;
&lt;li&gt;Exact command executed with full output&lt;/li&gt;
&lt;li&gt;File transfers with size and timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike SSH, where logs are scattered across servers, everything is centralized.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Simple Token Rotation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Alpacon:&lt;/strong&gt; Update token in workspace → Update GitHub Secrets once → Done&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSH:&lt;/strong&gt; Generate keys for each server → Update &lt;code&gt;authorized_keys&lt;/code&gt; everywhere → Update Secrets in every repo → Debug failures&lt;/p&gt;
&lt;h2&gt;
  
  
  Usage: Familiar Workflow, Better Security
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Remote Command Execution (alpacon-websh-action)
&lt;/h3&gt;

&lt;p&gt;Execute shell commands on remote servers, deployments, restarts, health checks, anything you'd do over SSH.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Alpacon CLI&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpacax/alpacon-setup-action@v1.0.0&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy application&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpacax/alpacon-websh-action@v1.1.0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;workspace-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ALPACON_WORKSPACE_URL }}&lt;/span&gt;
    &lt;span class="na"&gt;api-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ALPACON_API_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;your-server'&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;cd /app&lt;/span&gt;
      &lt;span class="s"&gt;git pull&lt;/span&gt;
      &lt;span class="s"&gt;npm install&lt;/span&gt;
      &lt;span class="s"&gt;pm2 restart app&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Restart system service (with root access)&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpacax/alpacon-websh-action@v1.1.0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;workspace-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ALPACON_WORKSPACE_URL }}&lt;/span&gt;
    &lt;span class="na"&gt;api-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ALPACON_API_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;your-server'&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;systemctl restart nginx&lt;/span&gt;
    &lt;span class="na"&gt;as-root&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  File Transfer (alpacon-cp-action)
&lt;/h3&gt;

&lt;p&gt;Upload build artifacts, download logs, sync directories, everything you'd use SCP for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Alpacon CLI&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpacax/alpacon-setup-action@v1.0.0&lt;/span&gt;

&lt;span class="c1"&gt;# Upload files to server&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload build artifacts&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpacax/alpacon-cp-action@v1.1.0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;workspace-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ALPACON_WORKSPACE_URL }}&lt;/span&gt;
    &lt;span class="na"&gt;api-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ALPACON_API_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./dist/'&lt;/span&gt;
    &lt;span class="na"&gt;target-server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;prod-server'&lt;/span&gt;
    &lt;span class="na"&gt;target-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/var/www/app/'&lt;/span&gt;
    &lt;span class="na"&gt;recursive&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="c1"&gt;# Download files from server&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Download logs for analysis&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpacax/alpacon-cp-action@v1.1.0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;workspace-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ALPACON_WORKSPACE_URL }}&lt;/span&gt;
    &lt;span class="na"&gt;api-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ALPACON_API_TOKEN }}&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/var/log/app/error.log'&lt;/span&gt;
    &lt;span class="na"&gt;target-server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;prod-server'&lt;/span&gt;
    &lt;span class="na"&gt;target-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./logs/'&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;download&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites: Register Your Servers
&lt;/h3&gt;

&lt;p&gt;Before using these GitHub Actions, you need to register your servers with Alpacon:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a workspace&lt;/strong&gt; at &lt;a href="https://alpacon.io" rel="noopener noreferrer"&gt;alpacon.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install Alpacon agent&lt;/strong&gt; on your servers using the provided install script&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify servers are connected&lt;/strong&gt; in your workspace dashboard&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;📘 &lt;strong&gt;Full guide&lt;/strong&gt;: &lt;a href="https://docs.alpacax.com/learn/quickstart/" rel="noopener noreferrer"&gt;Alpacon Documentation - Quickstart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once your servers are registered and showing as "CONNECTED" in your workspace, you can use them from GitHub Actions.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Generate API Token
&lt;/h3&gt;

&lt;p&gt;In your workspace settings, create an API token with appropriate command ACLs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ile1jgazhuu13gbj488.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ile1jgazhuu13gbj488.png" alt=" " width="800" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Add Secrets to GitHub
&lt;/h3&gt;

&lt;p&gt;Add these secrets to your repository (or organization for shared access):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALPACON_WORKSPACE_URL: https://alpacon.io/your-workspace
ALPACON_API_TOKEN: your-token-here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Use the Actions
&lt;/h3&gt;

&lt;p&gt;Start with &lt;code&gt;alpacon-setup-action&lt;/code&gt;, then add other actions as needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four Actions
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Example Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;alpacon-setup-action&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Install Alpacon CLI&lt;/td&gt;
&lt;td&gt;Always run first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;alpacon-websh-action&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Execute remote commands&lt;/td&gt;
&lt;td&gt;Deploy, restart services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;alpacon-cp-action&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Transfer files&lt;/td&gt;
&lt;td&gt;Upload builds, download logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;alpacon-common-action&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Run any Alpacon command&lt;/td&gt;
&lt;td&gt;List servers, check status&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.alpacax.com/" rel="noopener noreferrer"&gt;Alpacon Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/setup-alpacon-cli" rel="noopener noreferrer"&gt;GitHub Marketplace - Setup Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/alpacon-websh-action" rel="noopener noreferrer"&gt;GitHub Marketplace - Websh Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/alpacon-cp-action" rel="noopener noreferrer"&gt;GitHub Marketplace - CP Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/alpacon-common-action" rel="noopener noreferrer"&gt;GitHub Marketplace - Common Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/alpacax/what-do-you-think-about-the-way-we-still-use-ssh-for-server-access-2j52"&gt;Previous Article: SSH Problems&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;SSH served us well for 30 years. But modern infrastructure demands modern solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API tokens&lt;/strong&gt; instead of SSH keys&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command ACLs&lt;/strong&gt; instead of full access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit logs&lt;/strong&gt; instead of manual investigation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero exposed ports&lt;/strong&gt; instead of internet-facing SSH&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralized management&lt;/strong&gt; instead of per-repo configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alpacon GitHub Actions make these benefits accessible in your CI/CD pipelines today.&lt;/p&gt;

&lt;p&gt;Try it in your next deployment and see the difference.&lt;/p&gt;




&lt;h3&gt;
  
  
  Questions of feedback?
&lt;/h3&gt;

&lt;p&gt;We'd love to hear from you in our Discord community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 Join our Discord&lt;/strong&gt;: [&lt;a href="https://discord.gg/wadWh8VsYB" rel="noopener noreferrer"&gt;https://discord.gg/wadWh8VsYB&lt;/a&gt;]&lt;br&gt;
&lt;strong&gt;or drop a comment below!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Want hands-on experience with extra rewards?
&lt;/h3&gt;

&lt;p&gt;We're running a beta testing program where you can explore GitHub Actions integration and earn rewards while helping us improve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 Join the beta&lt;/strong&gt;: [&lt;a href="https://forms.gle/t1rcgXgyPfZewYgF8" rel="noopener noreferrer"&gt;https://forms.gle/t1rcgXgyPfZewYgF8&lt;/a&gt;]&lt;/p&gt;

</description>
      <category>devops</category>
      <category>github</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What do you think about the way we still use SSH for server access?</title>
      <dc:creator>AlpacaX</dc:creator>
      <pubDate>Mon, 22 Sep 2025 05:52:31 +0000</pubDate>
      <link>https://dev.to/alpacax/what-do-you-think-about-the-way-we-still-use-ssh-for-server-access-2j52</link>
      <guid>https://dev.to/alpacax/what-do-you-think-about-the-way-we-still-use-ssh-for-server-access-2j52</guid>
      <description>&lt;p&gt;For decades, SSH has been the default way to access and manage servers. &lt;br&gt;
It works, it’s powerful, and it’s everywhere.&lt;br&gt;
But as our teams and infrastructure grew, we started noticing more and more friction.&lt;/p&gt;

&lt;p&gt;Some of the pain points we faced were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managing keys and permissions across many users was messy and time-consuming&lt;/li&gt;
&lt;li&gt;Simple human errors sometimes caused outages or risky changes&lt;/li&gt;
&lt;li&gt;There was no easy way to collaborate in real-time on the same server session&lt;/li&gt;
&lt;li&gt;Security concerns grew around credential rotation and temporary access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These experiences made us rethink how server access should work.&lt;br&gt;
That’s why we started building Alpacon, a platform designed to simplify access, improve collaboration, and reduce human mistakes.&lt;br&gt;
Of course, this isn’t a problem only our team faces. Many developers, DevOps engineers, and security teams must have run into the same issues.&lt;/p&gt;

&lt;p&gt;So we’re curious: How do you feel about this?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is SSH still “good enough” for your workflow?&lt;/li&gt;
&lt;li&gt;Or do you also feel the need for something new?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’d love to hear your thoughts and keep this discussion going.&lt;/p&gt;

&lt;p&gt;To make it easier, we opened a Discord community where we share ideas about DevOps, security, and infrastructure access.&lt;br&gt;
: &lt;a href="https://discord.com/invite/wadWh8VsYB" rel="noopener noreferrer"&gt;https://discord.com/invite/wadWh8VsYB&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking forward to your perspectives!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cybersecurity</category>
      <category>ssh</category>
      <category>discuss</category>
    </item>
    <item>
      <title>discord</title>
      <dc:creator>AlpacaX</dc:creator>
      <pubDate>Mon, 22 Sep 2025 05:36:35 +0000</pubDate>
      <link>https://dev.to/alpacax/discord-2nkj</link>
      <guid>https://dev.to/alpacax/discord-2nkj</guid>
      <description></description>
    </item>
  </channel>
</rss>
