Overview
The ANDO CI Server runs your build.csando scripts automatically when you push to GitHub. It provides a web interface for monitoring builds, viewing logs, and managing projects.
Features
- GitHub App Integration: Receives webhooks on push events and reports build status back to GitHub.
- Real-Time Updates: Build status changes and system updates are pushed to the web UI via SignalR — dashboards and project lists refresh automatically.
- Rootless Docker: Runs under rootless Docker for enhanced security. Build containers are isolated.
- Automatic HTTPS: Caddy reverse proxy automatically obtains and renews Let’s Encrypt certificates.
- Automated Backups: Daily backups with 7-day daily + 12-month monthly retention.
Installation
Linux/Ubuntu Server
Run the installer from your local machine:
curl -fsSL https://andobuild.com/server-install.sh | bash -s user@your-server-ip
Install Options
# Build image locally instead of pulling from ghcr.io
./server-install.sh --build-local user@your-server-ip
# Use an existing SQL Server instead of deploying a container
./server-install.sh --external-sql user@your-server-ip
Create SQL Database and User (External SQL)
If you install with --external-sql, create a dedicated database and login first.
Connect to your SQL Server using any SQL client (Azure Data Studio, SSMS, sqlcmd, etc.):
# Example using sqlcmd
sqlcmd -S YOUR_SERVER_IP,1433 -U sa -P 'YOUR_SA_PASSWORD' -C
Run these SQL commands to create the database and dedicated login for ANDO:
-- Create database
CREATE DATABASE AndoServer;
GO
-- Create login with a strong password
CREATE LOGIN ando WITH PASSWORD = 'YourSecurePassword123!';
GO
-- Create user and grant permissions
USE AndoServer;
GO
CREATE USER ando FOR LOGIN ando;
GO
ALTER ROLE db_owner ADD MEMBER ando;
GO
Type exit to quit sqlcmd.
Then set your server connection string in /opt/ando/config/.env:
ConnectionStrings__DefaultConnection=Server=YOUR_SERVER_IP,1433;Database=AndoServer;User Id=ando;Password=YourSecurePassword123!;TrustServerCertificate=true;Encrypt=true
TrueNAS SCALE
For TrueNAS SCALE installations, see the dedicated guide: TrueNAS Installation
This guide covers installing ANDO as a custom app using the TrueNAS Apps interface.
GitHub App Configuration
Create a GitHub App with these settings:
| Setting | Value |
|---|---|
| Homepage URL | https://your-domain.com |
| Callback URL | https://your-domain.com/auth/github/callback |
| Webhook URL | https://your-domain.com/webhooks/github |
Required Permissions
| Permission | Access |
|---|---|
| Contents | Read |
| Metadata | Read |
| Commit statuses | Read and write |
Events
Subscribe to: Push, Pull request
Server Configuration
Configure the server’s public URL in your .env file. This is required for generating links in emails (verification, password reset).
Server__BaseUrl=https://ci.yourdomain.com
The URL must include the scheme (https://) and should not have a trailing slash.
Docker-in-Docker Builds
When a build requires DIND mode (e.g., Docker.Build, Docker.Push), the server automatically installs the Docker CLI inside the build container if it is not already present. This supports Alpine and Debian/Ubuntu-based images. You do not need to call Docker.Install() in your build script when running on the CI server — though it is harmless to include.
Git Identity in Build Containers
The CI server automatically configures a git committer identity (user.name and user.email) inside build containers so that operations like Git.Tag() (annotated tags) work without manual setup.
Defaults: Ando Server / ando-server@localhost
Override via environment variables (checked in order of priority):
GIT_COMMITTER_NAME/GIT_COMMITTER_EMAIL(standard git env vars)GIT_AUTHOR_NAME/GIT_AUTHOR_EMAILGIT_USER_NAME/GIT_USER_EMAIL
Set these in your .env.ando file or CI environment to customize the identity used for tags and commits in your builds. If git config user.name is already set in the container image, the server will not override it.
Docker Security
By default, ANDO CI Server validates that Docker is running in rootless mode for enhanced security. On platforms where Docker runs as root and cannot be configured for rootless mode (such as TrueNAS SCALE), you can bypass this check:
Build__AcknowledgeRootDockerRisk=true
Warning: Running Docker as root allows container escapes to gain root access to the host system. Only use this option on platforms that require it.
Optional In-App Self-Update (Admin)
ANDO can optionally show admins when a newer ghcr.io/aduggleby/ando-server:latest image is available and let them trigger an update from the web UI.
Enable it in /opt/ando/config/.env:
SelfUpdate__Enabled=true
Optional overrides:
SelfUpdate__Image=ghcr.io/aduggleby/ando-server:latest
SelfUpdate__ComposeFilePath=/opt/ando/docker-compose.yml
SelfUpdate__ServiceName=ando-server
SelfUpdate__ContainerName=ando-server
SelfUpdate__CheckIntervalMinutes=5
SelfUpdate__HelperImage=docker:27-cli
How it works:
- The server checks for updates every 5 minutes (configurable).
- If a newer image is found, admins see an update bar in the UI.
- Clicking update queues a background job that starts a helper Docker CLI container to run:
docker compose pull ando-serverdocker compose up -d ando-server
- After triggering an update, a full-screen overlay appears with a 30-second countdown while the container restarts, then automatically reconnects by polling the
/healthendpoint and reloads the page when the server is back. - The web UI also detects version changes independently — if the server is updated externally (e.g., by another admin or via SSH), all open browser tabs automatically clear caches and reload within 60 seconds.
If disabled (default), no update checks or update UI are shown.
User Registration
By default, anyone can register an account on the server. The first user to register automatically becomes an admin. Admins can disable new user self-registration from the Admin panel, which toggles the setting in the database (SystemSettings.AllowUserRegistration). When registration is disabled, the /api/auth/register endpoint returns an error for all users except the first (initial setup is always allowed).
Rate Limiting
The server applies per-IP sliding-window rate limits to protect against abuse. Rate limiting is enabled by default. Configure limits in your .env file:
| Policy | Env Prefix | Default | Purpose |
|---|---|---|---|
webhook | RateLimiting__Webhook__ | 30 req/60s | GitHub webhook endpoint |
api | RateLimiting__Api__ | 100 req/60s | Authenticated API endpoints (partitioned by user when logged in) |
auth | RateLimiting__Auth__ | 10 req/60s | Legacy auth fallback |
auth-sensitive | RateLimiting__AuthSensitive__ | 6 req/60s | Login, register, password reset |
auth-verification | RateLimiting__AuthVerification__ | 20 req/60s | Email verification, resend |
Each policy supports three settings: PermitLimit, WindowSeconds, and QueueLimit. Example override:
RateLimiting__AuthSensitive__PermitLimit=10
RateLimiting__AuthSensitive__WindowSeconds=120
To disable rate limiting entirely:
RateLimiting__Enabled=false
Email Configuration
ANDO requires an email service for user registration, password reset, and build failure notifications. Configure one of the following providers in your .env file:
Option A: Resend-Compatible API (Recommended)
Email__Provider=Resend
Email__FromAddress=noreply@yourdomain.com
Email__Resend__ApiKey=your_api_key
Email__Resend__BaseUrl=https://api.selfmx.com/
Works with any Resend-compatible email API such as SelfMX. For the official Resend service, omit BaseUrl or set it to https://api.resend.com/.
Option B: SMTP
Email__Provider=Smtp
Email__FromAddress=noreply@yourdomain.com
Email__Smtp__Host=smtp.yourdomain.com
Email__Smtp__Port=587
Email__Smtp__Username=your-username
Email__Smtp__Password=your-password
Email__Smtp__UseSsl=true
Works with any SMTP provider (Gmail, SendGrid, Mailgun, your own mail server, etc.)
API Tokens
Personal API tokens allow programmatic access to the ANDO CI Server REST API. Use tokens for CI scripts, automation, or any tool that needs to authenticate without a browser session.
Creating a Token
Create tokens via the REST API (requires cookie-based authentication first):
# Login to get a session cookie
curl -c cookies.txt -X POST https://ci.yourdomain.com/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com","password":"..."}'
# Create a token
curl -b cookies.txt -X POST https://ci.yourdomain.com/api/auth/tokens \
-H 'Content-Type: application/json' \
-d '{"name":"CI automation"}'
The response includes the token value once — store it securely. Tokens have the format ando_pat_<random>.
Authenticating with a Token
Pass the token via the Authorization header or the X-Api-Token header:
# Using Authorization header
curl -H 'Authorization: Bearer ando_pat_...' https://ci.yourdomain.com/api/projects
# Using X-Api-Token header
curl -H 'X-Api-Token: ando_pat_...' https://ci.yourdomain.com/api/projects
Token Endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /api/auth/tokens | Create a new token. Body: {"name":"..."} |
GET | /api/auth/tokens | List all your tokens (metadata only, not the raw value). |
DELETE | /api/auth/tokens/{id} | Revoke a token. |
Helper Script
A helper script is included for creating tokens via Playwright’s API context:
ANDO_BASE_URL=https://ci.yourdomain.com \
ANDO_EMAIL=you@example.com \
ANDO_PASSWORD=... \
ANDO_TOKEN_NAME="CI automation" \
node tests/Ando.Server.E2E/tools/create-api-token.js
Health Checks
The server exposes health endpoints for monitoring and load balancers.
Basic Health (GET /health)
Returns 200 with {"status": "healthy"} when the server can connect to and query the database. Returns 503 with {"status": "unhealthy", "error": "..."} when the database is unreachable. No authentication required.
Use this endpoint for Docker health checks, load balancer probes, and uptime monitoring.
System Health (GET /api/admin/system-health)
Admin-only endpoint that runs live probes against all subsystems:
| Check | What It Tests |
|---|---|
| Database | Connectivity and query execution |
| Background Jobs | Hangfire worker availability |
| GitHub Integration | GitHub App authentication |
Each check returns a status of healthy, warning, or error with a descriptive message. Results are displayed in the admin dashboard.
Server Management
Management scripts installed to /opt/ando/scripts/:
sudo -u ando /opt/ando/scripts/status.sh # View container status
sudo -u ando /opt/ando/scripts/logs.sh # View logs
sudo -u ando /opt/ando/scripts/restart.sh # Restart services
sudo -u ando /opt/ando/scripts/update.sh # Pull latest and restart
sudo -u ando /opt/ando/scripts/backup.sh # Run backup now
File Locations
| Path | Description |
|---|---|
/opt/ando/docker-compose.yml | Docker Compose configuration |
/opt/ando/config/.env | Environment configuration |
/opt/ando/scripts/ | Management scripts |
/opt/ando/backups/ | Automated backups |
/opt/ando/data/sqldata/ | SQL Server database |
/opt/ando/data/keys/ | ASP.NET Data Protection keys (auth sessions) |
/opt/ando/data/artifacts/ | Build artifacts |
Full Documentation
https://github.com/aduggleby/ando/blob/main/src/Ando.Server/README.md