GitHub Actions integration
Automate deployments and server management with Alpacon’s purpose-built GitHub Actions.
Available actions
Alpacon provides four GitHub Actions for CI/CD workflows:
| Action | Purpose | Use case |
|---|---|---|
| alpacon-setup-action | Install Alpacon CLI | Always run first |
| alpacon-websh-action | Execute remote commands | Deploy apps, restart services |
| alpacon-cp-action | Transfer files | Upload builds, download logs |
| alpacon-common-action | Run any Alpacon command | List servers, check status |
For full input details, see Actions reference.
Quick start
1. Create a service token
CI and automation run on service tokens. A service token belongs to an application rather than to a person, so it survives staff changes, and its ACL bounds exactly what the pipeline may do.
- Go to IAM → Applications and open the application this pipeline belongs to, or create one.
- Open the Credentials tab and click Add.
- Name the token, choose its scopes, and write the reason it is needed.
- Copy the key when it is shown. It starts with
alpst-, and it is shown only once.
A token scoped for CI is reviewed before it works: the request is created as pending and authenticates nowhere until someone with approval rights activates it. Allow for that step rather than discovering it mid-pipeline.
2. Add the ACL rules
A new service token reaches nothing until you add ACL rules. Servers, commands, and file paths are each deny-by-default, so a token with no rules is refused everywhere.
Open the token, go to its ACL tab, and add:
| Rule | What it bounds |
|---|---|
| Server ACL | Which servers the pipeline may reach |
| Command ACL | Which commands it may run, for example git pull, npm install, pm2 restart app |
| File ACL | Which paths it may upload to or download from |
A file transfer checks the server rule first, then the file rule. Skip the ACL tab and the workflow fails on its first command.
3. Add secrets to GitHub
Add these secrets to your repository (Settings → Secrets → Actions):
ALPACON_WORKSPACE_URL: https://your-workspace.us1.alpacon.io
ALPACON_SERVICE_TOKEN: alpst-your-token-here
The action input is named api-token and takes the service token as-is. The name is kept for compatibility with published workflows.
4. Use in workflow
name: Deploy with Alpacon
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Alpacon CLI
uses: alpacax/alpacon-setup-action@v1
- name: Deploy to production
uses: alpacax/alpacon-websh-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
target: 'prod-server'
script: |
cd /opt/myapp
git pull
npm install
pm2 restart app
Alternative: using Alpacon CLI container
If you prefer to use the Alpacon CLI directly without the pre-built actions, you can use the official Docker container.
On this path the CLI signs in to Alpacon Cloud with the workspace name and region rather than a URL, so add two more secrets:
ALPACON_WORKSPACE: your-workspace
ALPACON_REGION: us1
ALPACON_WORKSPACE_URL stays as it is, feeding the workspace-url input on the four actions; ALPACON_SERVICE_TOKEN serves both paths.
name: Deploy with Alpacon CLI
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
container:
image: alpacax/alpacon-cli:latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Login to Alpacon
run: alpacon login --workspace ${{ secrets.ALPACON_WORKSPACE }} --region ${{ secrets.ALPACON_REGION }} -t ${{ secrets.ALPACON_SERVICE_TOKEN }}
- name: Deploy to production
run: |
alpacon websh prod-server "cd /opt/myapp && git pull && npm install && pm2 restart app"
- name: Upload build artifacts
run: |
alpacon cp -r ./dist/ prod-server:/var/www/app/
This approach provides direct CLI access with minimal setup and is useful for complex workflows requiring multiple CLI commands.
Usage examples
All examples below assume
alpacon-setup-actionhas already run in an earlier step. See the quick start section for a complete workflow.
Execute commands as root
- name: Restart nginx
uses: alpacax/alpacon-websh-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
target: 'web-server'
username: 'root'
script: systemctl restart nginx
Execute commands as specific user
- name: Deploy as ubuntu user
uses: alpacax/alpacon-websh-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
target: 'web-server'
username: 'ubuntu'
script: |
cd /home/ubuntu/app
git pull
npm install
Execute commands with specific user and group
- name: Deploy with www-data group
uses: alpacax/alpacon-websh-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
target: 'web-server'
username: 'ubuntu'
groupname: 'www-data'
script: cp -r /tmp/build/* /var/www/html/
Pass environment variables
- name: Deploy with environment variables
uses: alpacax/alpacon-websh-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
target: 'prod-server'
env: |
APP_ENV=production
DB_HOST=localhost
script: |
echo "Deploying to $APP_ENV"
systemctl restart myapp
Upload build artifacts
- name: Build application
run: npm run build
- name: Upload build to server
uses: alpacax/alpacon-cp-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
source: './dist/'
target-server: 'prod-server'
target-path: '/var/www/app/'
recursive: true
Upload multiple files
- name: Upload config files
uses: alpacax/alpacon-cp-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
source: |
./docker-compose.yml
./nginx.conf
./.env.production
target-server: 'prod-server'
target-path: '/opt/myapp/'
Download logs
- name: Download error logs
uses: alpacax/alpacon-cp-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
source: '/var/log/app/error.log'
target-server: 'prod-server'
target-path: './logs/'
mode: download
- name: Upload logs as artifact
uses: actions/upload-artifact@v4
with:
name: error-logs
path: ./logs/
Multi-server deployment
jobs:
deploy:
runs-on: ubuntu-latest
strategy:
matrix:
server: [web1, web2, web3]
steps:
- uses: actions/checkout@v4
- name: Setup Alpacon CLI
uses: alpacax/alpacon-setup-action@v1
- name: Deploy to ${{ matrix.server }}
uses: alpacax/alpacon-websh-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
target: ${{ matrix.server }}
script: |
cd /opt/myapp
git pull
npm install
pm2 restart app
Run any Alpacon command
- name: List all servers
uses: alpacax/alpacon-common-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
command: "server ls"
Docker deployment with environment selection
Deploy containerized applications to different environments with dynamic server selection:
name: Deploy Application
on:
workflow_dispatch:
inputs:
env:
description: "Deployment environment"
required: true
type: choice
options:
- dev
- prod
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Select target server
run: |
if [ "${{ inputs.env }}" = "prod" ]; then
echo "TARGET_SERVER=prod-server" >> $GITHUB_ENV
echo "APP_PORT=8080" >> $GITHUB_ENV
else
echo "TARGET_SERVER=dev-server" >> $GITHUB_ENV
echo "APP_PORT=8081" >> $GITHUB_ENV
fi
- name: Prepare environment file
run: |
echo "APP_ENV=${{ inputs.env }}" > /tmp/.env
echo "APP_PORT=${{ env.APP_PORT }}" >> /tmp/.env
echo '${{ secrets.APP_SECRETS }}' >> /tmp/.env
- name: Setup Alpacon CLI
uses: alpacax/alpacon-setup-action@v1
- name: Docker login on target server
uses: alpacax/alpacon-websh-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
target: ${{ env.TARGET_SERVER }}
script: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
- name: Copy docker-compose.yml
uses: alpacax/alpacon-cp-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
source: ./docker-compose.yml
target-server: ${{ env.TARGET_SERVER }}
target-path: /opt/myapp/docker-compose.yml
- name: Copy environment file
uses: alpacax/alpacon-cp-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
source: /tmp/.env
target-server: ${{ env.TARGET_SERVER }}
target-path: /opt/myapp/.env
- name: Deploy application
uses: alpacax/alpacon-websh-action@v1
with:
workspace-url: ${{ secrets.ALPACON_WORKSPACE_URL }}
api-token: ${{ secrets.ALPACON_SERVICE_TOKEN }}
target: ${{ env.TARGET_SERVER }}
script: |
docker compose -f /opt/myapp/docker-compose.yml pull
docker compose -f /opt/myapp/docker-compose.yml --env-file /opt/myapp/.env up -d
docker compose -f /opt/myapp/docker-compose.yml ps
Best practices
- Create dedicated tokens for CI/CD with minimal permissions
- Use command ACL to restrict which commands tokens can execute
- Store tokens as secrets—never commit them to your repository
- Rotate tokens regularly in workspace, then update GitHub secrets
- Use organization secrets for tokens shared across repositories
- All commands are recorded in workspace audit logs with sensitive values automatically masked
Resources
- Actions reference
- Alpacon CLI documentation
- GitHub Marketplace - Setup Action
- GitHub Marketplace - Websh Action
- GitHub Marketplace - CP Action
- GitHub Marketplace - Common Action