Last Updated: January 3, 2026 at 03:20 UTC

n8n Workflow Export & Import

Export All Workflows

BASH

Export all n8n workflows to JSON files for backup/version control

# Using n8n CLI (if installed)
n8n export:workflow --all --output=./workflows/

# Or via API
curl -u "admin:password" \
  "http://10.0.0.250:5678/api/v1/workflows" \
  | jq '.data[] | {name: .name, id: .id}' > workflows-list.json

# Export individual workflow
curl -u "admin:password" \
  "http://10.0.0.250:5678/api/v1/workflows/1" \
  > workflow-scan-intake.json

Import Workflow from JSON

BASH
# Via n8n CLI
n8n import:workflow --input=./workflow-scan-intake.json

# Via API
curl -X POST "http://10.0.0.250:5678/api/v1/workflows" \
  -u "admin:password" \
  -H "Content-Type: application/json" \
  -d @workflow-scan-intake.json

Activate/Deactivate Workflow

BASH
# Activate workflow
curl -X PATCH "http://10.0.0.250:5678/api/v1/workflows/1" \
  -u "admin:password" \
  -H "Content-Type: application/json" \
  -d '{"active": true}'

# Deactivate workflow
curl -X PATCH "http://10.0.0.250:5678/api/v1/workflows/1" \
  -u "admin:password" \
  -H "Content-Type: application/json" \
  -d '{"active": false}'

PostgreSQL Commands

Connect to Database

BASH
# Connect to PostgreSQL container on bennybeen (10.0.0.250)
docker exec -it mm-postgres psql -U mm_user -d madmonkey

# Or from host (if port exposed)
psql -h 10.0.0.250 -U mm_user -d madmonkey

# Connection string format
postgresql://mm_user:PASSWORD@10.0.0.250:5432/madmonkey

Create Database and Tables

SQL
-- Create database
CREATE DATABASE madmonkey;

-- Connect to database
\c madmonkey

-- Create cards table
CREATE TABLE cards (
    qr_id VARCHAR(10) PRIMARY KEY,
    type VARCHAR(10) NOT NULL,
    status VARCHAR(20) DEFAULT 'active',
    current_slug VARCHAR(50),
    move_code VARCHAR(20) UNIQUE,
    last_scan_ts TIMESTAMP,
    last_scan_city VARCHAR(100),
    total_scans INTEGER DEFAULT 0,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

-- Add indexes
CREATE INDEX idx_cards_type ON cards(type);
CREATE INDEX idx_cards_status ON cards(status);
CREATE INDEX idx_cards_last_scan_ts ON cards(last_scan_ts);

Common Queries

SQL
-- Get all verified entries for current month
SELECT * FROM entries
WHERE verified = true
  AND month_bucket = TO_CHAR(NOW(), 'YYYY-MM')
ORDER BY created_at DESC;

-- Get top 10 most scanned cards
SELECT qr_id, type, total_scans, last_scan_city
FROM cards
ORDER BY total_scans DESC
LIMIT 10;

-- Find stuck cards (no scans in 10+ days)
SELECT qr_id, type, last_scan_ts, last_scan_city
FROM cards
WHERE last_scan_ts < NOW() - INTERVAL '10 days'
  AND status = 'active'
ORDER BY last_scan_ts ASC;

-- Get monthly contest entries by city
SELECT user_city, COUNT(*) as entries
FROM entries
WHERE verified = true
  AND month_bucket = '2024-12'
GROUP BY user_city
ORDER BY entries DESC;

-- Select random winner for the month
SELECT entry_id, email, name, qr_id
FROM entries
WHERE verified = true
  AND month_bucket = '2024-12'
ORDER BY RANDOM()
LIMIT 1;

Database Backup & Restore

BASH
# Backup database
docker exec mm-postgres pg_dump -U mm_user madmonkey > backup-$(date +%Y%m%d).sql

# Or with compression
docker exec mm-postgres pg_dump -U mm_user madmonkey | gzip > backup-$(date +%Y%m%d).sql.gz

# Restore database
docker exec -i mm-postgres psql -U mm_user madmonkey < backup-20241201.sql

# Restore from compressed backup
gunzip -c backup-20241201.sql.gz | docker exec -i mm-postgres psql -U mm_user madmonkey

Webhook Testing with cURL

Test Scan Webhook

BASH
# Simple GET request (simulates QR scan)
curl -L "https://hooks.mad-monkey-creations.com/scan?qr_id=T42"

# With custom headers (simulate mobile device)
curl -L "https://hooks.mad-monkey-creations.com/scan?qr_id=T42" \
  -H "User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15" \
  -H "X-Forwarded-For: 203.0.113.42"

# Follow redirects and show headers
curl -L -v "https://hooks.mad-monkey-creations.com/scan?qr_id=T42"

Test Entry Submission Webhook

BASH
# Submit test entry
curl -X POST "https://hooks.mad-monkey-creations.com/entry" \
  -H "Content-Type: application/json" \
  -d '{
    "qr_id": "T42",
    "email": "test@example.com",
    "name": "John Doe",
    "user_city": "Chicago, IL",
    "consent": true
  }'

# Submit with verbose output
curl -v -X POST "https://hooks.mad-monkey-creations.com/entry" \
  -H "Content-Type: application/json" \
  -d @test-entry.json

Create Short URLs

BASH
# Create single short URL (Shlink on bennybeen @ 10.0.0.250:8081)
curl -X POST "http://10.0.0.250:8081/rest/v3/short-urls" \
  -H "X-Api-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "longUrl": "https://hooks.mad-monkey-creations.com/scan?qr_id=T42",
    "customSlug": "T42",
    "domain": "mmlnk.us",
    "tags": ["benny", "traveler"]
  }'

# Bulk create short URLs (using loop)
for i in {1..10}; do
  QR_ID=$(printf "T%03d" $i)
  curl -X POST "http://10.0.0.250:8081/rest/v3/short-urls" \
    -H "X-Api-Key: your-api-key" \
    -H "Content-Type: application/json" \
    -d "{
      \"longUrl\": \"https://hooks.mad-monkey-creations.com/scan?qr_id=$QR_ID\",
      \"customSlug\": \"$QR_ID\",
      \"domain\": \"mmlnk.us\",
      \"tags\": [\"benny\", \"traveler\"]
    }"
  echo "Created: https://mmlnk.us/$QR_ID"
done

List and Search Short URLs

BASH
# List all short URLs
curl "http://10.0.0.250:8081/rest/v3/short-urls" \
  -H "X-Api-Key: your-api-key"

# Search by tag
curl "http://10.0.0.250:8081/rest/v3/short-urls?tags[]=traveler" \
  -H "X-Api-Key: your-api-key"

# Paginated results
curl "http://10.0.0.250:8081/rest/v3/short-urls?page=1&itemsPerPage=50" \
  -H "X-Api-Key: your-api-key"

Generate Shlink API Key

BASH
# Generate API key using Shlink CLI in container
docker exec mm-shlink shlink api-key:generate

# Generate with specific permissions
docker exec mm-shlink shlink api-key:generate \
  --name="n8n-integration" \
  --role-name="Domain"

# List all API keys
docker exec mm-shlink shlink api-key:list

Network & Port Scanning

Check Port Status

BASH
# Check if port is open (telnet) - All services on bennybeen (10.0.0.250)
telnet 10.0.0.250 5432

# Check with netcat
nc -zv 10.0.0.250 5432

# Check multiple ports on Docker host
for port in 5432 5678 8080 8081 9000; do
  nc -zv -w 2 10.0.0.250 $port
done

# Use nmap for comprehensive scan
nmap -p 5432,5678,8080,8081,9000 10.0.0.250

Check Service Availability

BASH
# Check if PostgreSQL is accepting connections (all services on 10.0.0.250)
pg_isready -h 10.0.0.250 -p 5432 -U mm_user

# Check HTTP services on bennybeen
curl -I http://10.0.0.250:8081  # Shlink
curl -I http://10.0.0.250:9000  # Listmonk

# Check with timeout
timeout 5 curl -I http://10.0.0.250:5678 || echo "n8n unavailable"

# Check all Mad Monkey services on single Docker host
for service in "10.0.0.250:5432" "10.0.0.250:5678" "10.0.0.250:8080" "10.0.0.250:8081" "10.0.0.250:9000"; do
  echo "Checking $service..."
  nc -zv -w 2 ${service/:/ } && echo "OK" || echo "FAILED"
done

Node.js Setup

Install Node.js via NVM

BASH
# Install NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

# Load NVM
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

# Install Node.js 24.12.0
nvm install 24.12.0
nvm use 24.12.0
nvm alias default 24.12.0

# Verify installation
node --version  # v24.12.0
npm --version   # 9.2.0

# Make available system-wide (create symlink)
sudo ln -s "$NVM_DIR/versions/node/$(nvm version)/bin/node" /usr/local/bin/node
sudo ln -s "$NVM_DIR/versions/node/$(nvm version)/bin/npm" /usr/local/bin/npm

Install QR Code Generator

BASH
# Install mini-qr globally
npm install -g mini-qr

# Or install locally in project
mkdir qr-generator && cd qr-generator
npm init -y
npm install mini-qr

# Generate QR code
mini-qr "https://mmlnk.us/T42" -o T42.png

# Generate SVG
mini-qr "https://mmlnk.us/T42" -o T42.svg -t svg

# Generate multiple QR codes
for i in {1..10}; do
  QR_ID=$(printf "T%03d" $i)
  mini-qr "https://mmlnk.us/$QR_ID" -o "qr-codes/${QR_ID}.png"
  echo "Generated: ${QR_ID}.png"
done

Email & DNS Verification

Check DNS Records

BASH
# Check A record
dig mmlnk.us A +short
dig mad-monkey-creations.com A +short

# Check MX record
dig mad-monkey-creations.com MX +short

# Check TXT records (SPF, DKIM, DMARC)
dig mad-monkey-creations.com TXT +short
dig _dmarc.mad-monkey-creations.com TXT +short
dig default._domainkey.mad-monkey-creations.com TXT +short

# Use nslookup (alternative)
nslookup -type=MX mad-monkey-creations.com
nslookup -type=TXT mad-monkey-creations.com

# Check DNS propagation
dig @8.8.8.8 mmlnk.us  # Google DNS
dig @1.1.1.1 mmlnk.us  # Cloudflare DNS

Test SMTP Connection

BASH
# Test SMTP with openssl (ForwardMail.net - ONLY email provider)
openssl s_client -connect smtp.forwardemail.net:587 -starttls smtp

# Send test email via command line
cat > test-email.txt << EOF
From: hello@mad-monkey-creations.com
To: test@example.com
Subject: Test Email

This is a test email from Mad Monkey Creations.
EOF

# Send via SMTP (requires mailx or similar)
cat test-email.txt | sendmail -v test@example.com

Docker Container Management

BASH
# Start all Mad Monkey containers
docker-compose -f docker-compose-postgres.yml up -d
docker-compose -f docker-compose-shlink.yml up -d
docker-compose -f docker-compose-listmonk.yml up -d

# Check container status
docker ps | grep mm-

# View logs
docker logs -f mm-postgres
docker logs -f mm-shlink --tail 100
docker logs -f mm-listmonk

# Restart containers
docker restart mm-postgres mm-shlink mm-listmonk

# Stop all containers
docker stop mm-postgres mm-shlink mm-listmonk

# Remove containers (data persists in volumes)
docker rm mm-postgres mm-shlink mm-listmonk

# View volumes
docker volume ls | grep mm

Environment Variables Template

BASH
# .env file for Mad Monkey project
# Copy to .env and fill in actual values
# All services run on single Docker host: bennybeen (10.0.0.250)

# Server Configuration
SERVER_HOST=10.0.0.250
EXTERNAL_IP=76.150.65.61  # DYNAMIC - can change!
PROJECT_PATH=/home/bennybeen/mad-monkey/

# PostgreSQL (on 10.0.0.250:5432)
POSTGRES_PASSWORD=YOUR_STRONG_PASSWORD_HERE
DB_HOST=10.0.0.250
DB_PORT=5432
DB_NAME=madmonkey
DB_USER=mm_user

# n8n (on 10.0.0.250:5678)
N8N_ENCRYPTION_KEY=GENERATE_RANDOM_KEY
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=YOUR_PASSWORD
N8N_URL=http://10.0.0.250:5678

# Listmonk (on 10.0.0.250:9000)
LISTMONK_URL=http://10.0.0.250:9000
LISTMONK_API_USER=admin
LISTMONK_API_PASSWORD=YOUR_PASSWORD
LISTMONK_LIST_ID=1

# Shlink (on 10.0.0.250:8081)
SHLINK_URL=http://10.0.0.250:8081
SHLINK_API_KEY=GENERATE_VIA_CLI
DEFAULT_DOMAIN=mmlnk.us

# Email (ForwardMail.net - ONLY provider)
SMTP_HOST=smtp.forwardemail.net
SMTP_PORT=587
SMTP_USER=hello@mad-monkey-creations.com
SMTP_PASS=YOUR_SMTP_PASSWORD
MM_SENDER_EMAIL=hello@mad-monkey-creations.com

# Application
MM_LANDING_BASE=https://www.mad-monkey-creations.com
MM_REWARD_URL=https://www.mad-monkey-creations.com/reward
MM_DISCOUNT_CODE=BANANAS10

# To load in shell:
# export $(cat .env | xargs)