Quick Start
Get Klixsor running on your server in under 5 minutes.
Get a VPS
Provision a fresh Ubuntu 22.04 or Debian 12 server from any provider (Contabo, Hetzner, DigitalOcean, Vultr, OVH, etc). See server requirements below.
Run the installer
SSH into your server as root and run:
curl -sSL https://klixsor.com/install.sh | bash -s -- YOUR-LICENSE-KEY
Replace YOUR-LICENSE-KEY with the license key from your purchase email. The installer handles everything — Docker, databases, binaries, firewall, and bot IP list seeding.
Save your credentials
When the installer finishes, it prints your admin login, password, and server URL. It also saves them to /opt/klixsor/credentials.txt.
Log in and configure
Open http://YOUR-SERVER-IP:8081 in your browser. Log in with the admin credentials. Add your tracking domain, create your first campaign, and you're live.
Server Requirements
| Component | Minimum | Recommended |
|---|---|---|
| OS | Ubuntu 20.04 / Debian 11 | Ubuntu 22.04 / Debian 12 |
| CPU | 2 vCPU | 4+ vCPU |
| RAM | 4 GB | 8+ GB |
| Storage | 40 GB SSD | 80+ GB NVMe SSD |
| Bandwidth | 1 TB/month | Unlimited / 5+ TB |
Ports Used
| Port | Service | Access |
|---|---|---|
| 22 | SSH | Public (your IP only recommended) |
| 80 | HTTP | Public |
| 443 | HTTPS | Public |
| 8081 | Admin API | Localhost only (behind Nginx) |
| 8090 | Click Engine | Localhost only (behind Nginx) |
| 5432 | PostgreSQL | Localhost only |
| 9000 | ClickHouse | Localhost only |
| 6379 | Redis | Localhost only |
Installation
What the installer does
- Installs system dependencies (curl, Docker, fail2ban, UFW)
- Sets up Docker containers for PostgreSQL 16, ClickHouse, and Redis 7
- Downloads Klixsor API and Click Engine binaries
- Runs database migrations
- Creates an admin user with a random password
- Configures systemd services for auto-start on boot
- Sets up UFW firewall (ports 22, 80, 443 only)
- Seeds 17 bot IP lists and triggers initial sync
Installation command
curl -sSL https://klixsor.com/install.sh | bash -s -- YOUR-LICENSE-KEY
Custom version
To install a specific version instead of the latest:
curl -sSL https://klixsor.com/install.sh | bash -s -- --version 1.2.0 YOUR-LICENSE-KEY
File locations
| Path | Contents |
|---|---|
/opt/klixsor/ | Binaries, config, license key, docker-compose |
/opt/klixsor/configs/config.yaml | Main configuration file |
/opt/klixsor/.env | Database passwords, JWT secret, license key |
/opt/klixsor/credentials.txt | Generated credentials (readable by root only) |
/opt/klixsor/license.key | Your license key |
/var/lib/klixsor/ | Database data (PostgreSQL, ClickHouse, Redis) |
/var/lib/klixsor/backups/ | Automatic pre-update backups |
First Steps After Install
- Log in — Open
http://YOUR-SERVER-IP/api/v1/auth/loginwith the credentials from the installer output - Add a tracking domain — Go to Domains → Add Domain. Point your domain's DNS A record to your server IP first.
- Set up SSL — Click the shield icon (Setup SSL) on your domain row. This auto-provisions a Let's Encrypt certificate — no manual certbot commands needed.
- Create a traffic source — Define where your traffic comes from (e.g., Facebook, Google Ads, push network)
- Add offers — Add the affiliate offers you want to route traffic to
- Create a campaign — Set up your first campaign with flows, landing pages, and offers
- Verify bot detection — Check Bot Management → IP Lists to confirm all lists are synced
- Check Settings — Go to Settings in the sidebar to verify your license status, version, and usage limits
Adding Domains
Adding a tracking domain to Klixsor is a 3-step process: configure DNS, add the domain in the admin panel, then provision SSL.
Step 1: Configure DNS
In your domain registrar (Namecheap, Cloudflare, GoDaddy, etc.), create a DNS record pointing to your Klixsor server.
For subdomains (recommended — e.g., track.yourdomain.com):
Type: A (or CNAME)
Name: track
Value: YOUR-SERVER-IP
TTL: 300 (or Auto)
For root domains (e.g., yourdomain.com):
Type: A
Name: @
Value: YOUR-SERVER-IP
TTL: 300 (or Auto)
Your server's IP is shown in the admin panel — the Domains page displays DNS setup instructions with the correct IP pre-filled.
Step 2: Add the domain in Klixsor
- Go to Domains → Add Domain
- Enter the full domain name (e.g.,
track.yourdomain.com) - Optionally set an Index Campaign to handle visitors to the domain root
- Save the domain
Step 3: Setup SSL
Click the shield icon (Setup SSL) on the domain row. Klixsor will automatically:
- Verify DNS is pointing to your server
- Create an Nginx server block for the domain
- Provision a free Let's Encrypt SSL certificate
- Configure HTTPS with automatic HTTP → HTTPS redirect
The entire process takes about 10 seconds. Once complete, the SSL column will show Enabled.
SSL / HTTPS Setup
SSL is critical for tracking domains. Without HTTPS, browsers will show security warnings and may block redirects and tracking pixels.
Automatic SSL (recommended)
Klixsor handles SSL automatically. When you click the Setup SSL button on a domain, it:
- Creates an Nginx server block for the domain
- Obtains a free Let's Encrypt certificate via
certbot - Configures HTTPS with automatic HTTP → HTTPS redirect
- Sets up automatic certificate renewal (via systemd timer)
No manual configuration required. The installer pre-installs Nginx and Certbot for you.
Manual SSL (advanced)
If you prefer manual control, you can provision certificates yourself:
# Get a certificate manually
certbot certonly --nginx -d track.yourdomain.com
# Or use standalone mode (stops nginx temporarily)
certbot certonly --standalone -d track.yourdomain.com
# Certificates renew automatically via systemd timer
systemctl list-timers | grep certbot
Cloudflare (if using Cloudflare DNS)
Set Cloudflare SSL mode to Full (Strict) and use Cloudflare's origin certificate.
Nginx Reverse Proxy
Nginx is installed and configured automatically by the Klixsor installer. It proxies HTTPS traffic to the Klixsor services running on localhost.
How it works
The installer creates a base Nginx config at /etc/nginx/sites-available/klixsor-admin that:
- Proxies
/api/requests to the Admin API (:8081) - Proxies all other requests to the Click Engine (
:8090)
When you click Setup SSL on a domain, Klixsor creates a dedicated Nginx config at /etc/nginx/sites-available/klixsor-trk-{domain} with SSL termination.
Config files
# Base config (created by installer)
/etc/nginx/sites-available/klixsor-admin
# Per-domain configs (created by Setup SSL)
/etc/nginx/sites-available/klixsor-trk-track.yourdomain.com
# Check all configs
nginx -t
# Reload after manual changes
systemctl reload nginx
Custom Nginx config (advanced)
If you need to customize the Nginx config for a domain (e.g., add custom headers, rate limiting), edit the per-domain config file directly:
# Edit the tracking domain config
nano /etc/nginx/sites-available/klixsor-trk-track.yourdomain.com
# Test and reload
nginx -t && systemctl reload nginx
Configuration File
The main configuration is at /opt/klixsor/configs/config.yaml. Here are the key sections:
server:
api_port: 8081 # Admin API port
click_port: 8090 # Click engine port
server_ip: "" # Auto-detected if empty
postgres:
host: localhost
port: 5432
user: klixsor
password: "your-password"
database: klixsor
max_conns: 20 # Connection pool size
clickhouse:
host: localhost
port: 9000
database: klixsor
redis:
addr: localhost:6379
password: "your-password"
db: 0
bot_detect:
score_threshold: 70 # Score >= 70 = definite bot (blocked)
challenge_threshold: 40 # Score 40-69 = suspicious (challenge page)
geoip:
db_path: "/var/lib/klixsor/GeoLite2-City.mmdb"
systemctl restart klixsor-api klixsor-clickengine
Creating Campaigns
Campaigns are the core of Klixsor. Each campaign has a unique URL that receives traffic and routes it based on your configured flows.
Campaign URL structure
https://track.yourdomain.com/CAMPAIGN-ALIAS?sub_id_1=value&sub_id_2=value
Campaign settings
| Setting | Description |
|---|---|
| Alias | URL slug for the campaign (e.g., my-offer) |
| Domain | Which tracking domain to use |
| Traffic Source | Where traffic originates (for reporting) |
| Cost Model | CPC, CPM, CPA, or Revenue Share |
| Uniqueness | How to count unique clicks (by IP, cookie, or both) |
| Safe Page | What to show bots/moderators (disabled, redirect, HTML, or proxy) |
Flows & Routing
Each campaign contains one or more flows. Flows determine which landing page and offer a visitor sees based on conditions you define.
Flow types
- Forced flow — Always used when its conditions match (top priority)
- Regular flow — Selected by weight among eligible flows
- Default flow — Fallback when no other flow matches
Flow conditions
Route traffic based on: country, device, OS, browser, language, connection type, ISP, referrer, sub ID values, day of week, hour of day, and more.
Landing Pages
Klixsor supports two types of landing pages:
Redirect landing pages
Klixsor redirects the visitor to your externally hosted landing page URL. The click URL is appended as a parameter so your page can link to the offer.
Local (hosted) landing pages
HTML stored and served directly by Klixsor. Use the Clone from URL feature to import any page:
- Click "Clone from URL" in the Landing Pages section
- Paste the URL of the page you want to clone
- Klixsor fetches the HTML, rewrites all relative URLs to absolute, and saves it
- Edit the HTML to add
{offer_url}placeholders in your CTA buttons
Available placeholders
| Placeholder | Replaced with |
|---|---|
{click_id} | Unique click identifier |
{offer_url} | Selected offer URL (for CTA links) |
{country} | Visitor's country code (US, GB, etc) |
{city} | Visitor's city name |
{device} | Device type (desktop, mobile, tablet) |
{os} | Operating system |
{browser} | Browser name |
{ip} | Visitor's IP address |
{sub_id_1} ... {sub_id_30} | Custom sub ID values |
Offers
Offers are the destination URLs where traffic is ultimately sent. Add your affiliate offer URLs with the appropriate tracking parameters.
Offer URL with macros
https://network.com/offer?click_id={click_id}&sub1={sub_id_1}&sub2={sub_id_2}
Klixsor replaces all {placeholder} tokens with actual values when redirecting the visitor.
Conversion Tracking
Track conversions by adding a postback URL to your affiliate network. When a conversion happens, the network sends a request to Klixsor with the click ID.
Postback URL format
https://track.yourdomain.com/postback?click_id={click_id}&payout={payout}&status=approved
Replace {click_id} and {payout} with your network's corresponding macros.
Conversion parameters
| Parameter | Required | Description |
|---|---|---|
click_id | Yes | The Klixsor click ID that was passed to the offer |
payout | No | Revenue amount (e.g., 2.50) |
status | No | approved, pending, or rejected (default: approved) |
transaction_id | No | External transaction/conversion ID |
Bot Detection — How It Works
Klixsor uses a multi-signal scoring system to detect bots. Every click is scored from 0 (human) to 255 (definite bot).
Detection signals
- IP reputation — Checked against 17 auto-synced datacenter/cloud IP lists (AWS, GCP, Azure, etc.)
- User agent analysis — Known bot UAs, suspicious patterns, empty/missing UA
- Header anomalies — Missing standard headers, unusual Accept-Language, etc.
- TLS fingerprint — Analyzes the TLS handshake for headless browser signatures
- DNS verification — Reverse DNS lookup for claimed crawlers (Googlebot, Bingbot)
Score thresholds
| Score | Classification | Default action |
|---|---|---|
| 0 – 39 | Human | Normal routing |
| 40 – 69 | Suspicious | Challenge page (configurable) |
| 70 – 255 | Bot | Safe page or block |
Bot Rules
Create custom rules to override bot scoring based on specific conditions. Rules are evaluated in priority order.
Conditions
Match on: IP address/range, user agent (contains/regex), country, ASN, referrer, header presence.
Actions
- Allow — Force-allow regardless of bot score
- Block — Return 403
- Safe page — Show the campaign's safe page
- Redirect — Send to a custom URL
- Challenge — Show a JavaScript challenge page
IP Lists
Klixsor auto-syncs 17 datacenter and cloud IP lists daily:
- Googlebot, Google Ads, Google Special Crawlers
- Bingbot, Applebot
- Facebook/Meta
- AWS, GCP, Azure, DigitalOcean, Oracle, Hetzner, OVH, Vultr, Linode, Scaleway, Cloudflare
Lists sync automatically on first install and every 24 hours thereafter. You can also add custom IP lists manually.
Updating Klixsor
Updates are safe and non-destructive. All your data, configuration, and credentials are preserved.
Check for updates
Go to Settings in the admin panel sidebar. The Version card shows:
- Current Version — the version running on your server
- Latest Version — the newest release available
- Update Available indicator — shown when a newer version exists
If an update is available, the Settings page displays the update command you need to run.
Update to the latest version
SSH into your server and run:
curl -sSL https://klixsor.com/install.sh | bash -s -- --update
What happens during an update
- Backup — PostgreSQL database dump + config files saved to
/var/lib/klixsor/backups/ - Stop — Click engine and API gracefully stopped
- Download — New binaries downloaded and validated (ELF header check prevents corrupt downloads)
- Migrate — New database migrations applied (idempotent, safe to re-run)
- Start — Services restarted
- Verify — Health check confirms everything is running
- Rollback — If the health check fails, old binaries and database are automatically restored
What's preserved
- All campaign, domain, and user data
- Click history and conversion data
- Configuration file (
config.yaml) - Database passwords and JWT secret (
.env) - License key
- Nginx configs and SSL certificates
- Firewall rules
- Admin credentials
Update to a specific version
curl -sSL https://klixsor.com/install.sh | bash -s -- --update --version 1.2.0
Skip backup (faster, not recommended)
curl -sSL https://klixsor.com/install.sh | bash -s -- --update --no-backup
Settings Page
The Settings page (accessible from the sidebar) provides a system overview with four information cards:
License
- Status — Active, Invalid, or Grace Period
- Plan — Your current subscription tier (Starter, Pro, Enterprise)
- License Key — Masked display of your license key
- Expires — License expiration date with a warning if expiring soon
Usage & Limits
Visual progress bars showing your current usage against plan limits:
- Campaigns — current / maximum campaigns
- Domains — current / maximum domains
- Users — current / maximum users
Bars turn yellow at 70% and red at 90% usage. "Unlimited" is shown for Enterprise plans.
Version
- Current Version — the version running on this server
- Latest Version — the newest version available from klixsor.com
- Update Available — indicator with the update command when a new version exists
Plan Features
Shows which features are included in your plan (e.g., landing page cloner, API access, custom bot rules). Only displayed when features are restricted by your plan.
Backups & Restore
Automatic backups
Every update creates an automatic backup at /var/lib/klixsor/backups/klixsor_backup_YYYYMMDD_HHMMSS/. The 5 most recent backups are kept.
Manual backup
# PostgreSQL dump
docker exec klixsor-postgres pg_dump -U klixsor -d klixsor \
--format=custom -f /tmp/klixsor_backup.dump
docker cp klixsor-postgres:/tmp/klixsor_backup.dump ./klixsor_backup.dump
# Config files
cp /opt/klixsor/configs/config.yaml ./config.yaml.bak
cp /opt/klixsor/.env ./.env.bak
Restore from backup
# Stop services
systemctl stop klixsor-api klixsor-clickengine
# Restore PostgreSQL
docker cp klixsor_backup.dump klixsor-postgres:/tmp/restore.dump
docker exec klixsor-postgres pg_restore -U klixsor -d klixsor \
--clean --if-exists /tmp/restore.dump
# Restore config
cp config.yaml.bak /opt/klixsor/configs/config.yaml
# Restart
systemctl start klixsor-api klixsor-clickengine
License Management
How licensing works
- Your license key is stored at
/opt/klixsor/license.key - Klixsor validates the license with the Klixsor license server every 6 hours
- If the server is unreachable, a 72-hour grace period allows continued operation
- Plan limits (campaigns, domains, users) are enforced based on your subscription tier
Update your license key
# Method 1: Via the update script
curl -sSL https://klixsor.com/install.sh | bash -s -- --update NEW-LICENSE-KEY
# Method 2: Manually
echo "NEW-LICENSE-KEY" > /opt/klixsor/license.key
systemctl restart klixsor-api klixsor-clickengine
Plan limits
| Resource | Starter | Pro | Enterprise |
|---|---|---|---|
| Campaigns | 10 | 50 | Unlimited |
| Domains | 3 | 10 | Unlimited |
| Users | 1 | 5 | Unlimited |
| Clicks/day | 100k | 1M | Unlimited |
| Data retention | 6 months | 12 months | Unlimited |
| Landing cloner | — | ✓ | ✓ |
| API access | — | ✓ | ✓ |
| Custom bot rules | — | — | ✓ |
Troubleshooting
Services won't start
# Check service status and logs
systemctl status klixsor-api
journalctl -u klixsor-api -n 50 --no-pager
systemctl status klixsor-clickengine
journalctl -u klixsor-clickengine -n 50 --no-pager
# Check if Docker containers are running
docker ps
Port already in use
# Find what's using port 8081
fuser 8081/tcp
# Kill the process
fuser -k 8081/tcp
# Restart
systemctl restart klixsor-api
Database connection failed
# Check if PostgreSQL is running
docker exec klixsor-postgres pg_isready -U klixsor
# Restart Docker containers
cd /opt/klixsor && docker compose --env-file .env up -d
# Verify password matches config
grep password /opt/klixsor/configs/config.yaml
grep POSTGRES_PASSWORD /opt/klixsor/.env
License validation errors
# Check license key
cat /opt/klixsor/license.key
# Test connectivity to license server
curl -s https://klixsor.com/api/license/validate
# Check logs for license errors
journalctl -u klixsor-api | grep license
Bot IP lists empty
Lists sync automatically on first install. If they're empty:
# Restart the API to trigger sync
systemctl restart klixsor-api
# Check logs for sync status
journalctl -u klixsor-api | grep "bot.*sync"
Need help?
Contact us at support@klixsor.com with your server's API logs and we'll help you get running.
API Authentication
The Klixsor API uses JWT tokens. Obtain a token by logging in, then include it in the Authorization header.
Login
curl -X POST https://admin.yourdomain.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"login": "admin", "password": "your-password"}'
# Response:
# { "token": "eyJhbGciOi...", "refresh_token": "..." }
Authenticated request
curl https://admin.yourdomain.com/api/v1/campaigns \
-H "Authorization: Bearer YOUR-JWT-TOKEN"
API Endpoints
All endpoints are under /api/v1/ and require JWT authentication (except login).
| Method | Path | Description |
|---|---|---|
POST | /auth/login | Login, get JWT token |
POST | /auth/refresh | Refresh JWT token |
GET | /auth/me | Current user info |
| Campaigns | ||
GET | /campaigns | List campaigns |
POST | /campaigns | Create campaign |
GET | /campaigns/:id | Get campaign |
PUT | /campaigns/:id | Update campaign |
DELETE | /campaigns/:id | Delete campaign |
POST | /campaigns/:id/clone | Clone campaign |
| Offers | ||
GET | /offers | List offers |
POST | /offers | Create offer |
PUT | /offers/:id | Update offer |
DELETE | /offers/:id | Delete offer |
| Domains | ||
GET | /domains | List domains |
POST | /domains | Add domain |
PUT | /domains/:id | Update domain |
DELETE | /domains/:id | Delete domain |
| Landing Pages | ||
GET | /landing-pages | List landing pages |
POST | /landing-pages | Create landing page |
POST | /landing-pages/clone-url | Clone page from URL |
PUT | /landing-pages/:id | Update landing page |
DELETE | /landing-pages/:id | Delete landing page |
| Reports | ||
POST | /reports/query | Run analytics query |
GET | /reports/dashboard | Dashboard stats |
GET | /reports/click-log | Raw click log |
| Conversions | ||
GET | /conversions | List conversions |
All list endpoints support ?page=1&per_page=50&sort_by=id&sort_dir=desc&search=term query parameters.
Postback URL
Configure this postback URL in your affiliate network to track conversions:
https://track.yourdomain.com/postback?click_id=REPLACE&payout=REPLACE&status=approved
Replace REPLACE with your network's macros for click ID and payout.