Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save oidebrett/5eb260124513f71674b5534c45da67cc to your computer and use it in GitHub Desktop.

Select an option

Save oidebrett/5eb260124513f71674b5534c45da67cc to your computer and use it in GitHub Desktop.
Setting up Komodo and Pangolin
I want you to help me writing another article in markdown format for a foundational article on how to install and set up komodo and pangolin
komodo is a tool to build and deploy software on many servers
Komodo is a web app to provide structure for managing your servers, builds, deployments, and automated procedures.
With Komodo you can:
Connect all of your servers, alert on CPU usage, memory usage, and disk usage, and connect to shell sessions.
Create, start, stop, and restart Docker containers on the connected servers, view their status and logs, and connect to container shell.
Deploy docker compose stacks. The file can be defined in UI, or in a git repo, with auto deploy on git push.
Build application source into auto-versioned Docker images, auto built on webhook. Deploy single-use AWS instances for infinite capacity.
Manage repositories on connected servers, which can perform automation via scripting / webhooks.
Manage all your configuration / environment variables, with shared global variable and secret interpolation.
Keep a record of all the actions that are performed and by whom.
Using a VPS
If you need a VPS to run Pangolin so we will use this for our komodo server too
Database choice
You need to choose which DB to use
Using MongoDB
Lower CPU usage, Higher RAM usage.
Some systems do not support running the latest MongoDB versions.
Using FerretDB (Postgres)
Lower RAM usage, Higher CPU usage.
I will use FerretDB in this example
Installation Steps
0. First we will correct the docker network that will underpin all our docker contains
```
docker network create pangolin
```
1. Downloading and Running the Installer
Copy komodo/ferretdb.compose.yaml and komodo/compose.env to your host:
wget -P komodo https://raw.githubusercontent.com/moghtech/komodo/main/compose/ferretdb.compose.yaml && \
wget -P komodo https://raw.githubusercontent.com/moghtech/komodo/main/compose/compose.env
we will do a minor change to the compose file to add a network at the end of the file
2. Edit the variables in komodo/compose.env.
I will leave the DB credentials for username as admin but use `openssl rand -base64 10` to generate my password
```
## DB credentials
KOMODO_DB_USERNAME=admin
KOMODO_DB_PASSWORD=CHANGEME
```
I will set the a secure passkey to authenticate between Core / Periphery using `openssl rand -base64 32`
```
KOMODO_PASSKEY=a_random_passkey
```
I will change the `KOMODO_HOST=https://demo.komo.do` to the url of my pangolin server with
```
KOMODO_HOST=https://komodo.yourdomain.com
```
I will change the webhook and jwt tokens again using `openssl rand -base64 32`
## Used to auth incoming webhooks. Alt: KOMODO_WEBHOOK_SECRET_FILE
KOMODO_WEBHOOK_SECRET=a_random_secret
## Used to generate jwt. Alt: KOMODO_JWT_SECRET_FILE
KOMODO_JWT_SECRET=a_random_jwt_secret
I will leave the local auth and we could use Pangolin for this also
```
KOMODO_LOCAL_AUTH=true
```
3. I will start the docker stack
```
cd komodo
```
Deploy:
```
docker compose -p komodo -f ferretdb.compose.yaml --env-file compose.env up -d
```
4. We then confirm its all working by going to
```
http://youripaddress:9120
```
you will pick a username/password and hit signup
4. Now I will use komodo to start install my pangolin instance
I will create a new stack and name it `pangolin-setup`
I Choose Mode and select `UI Defined` and paste in the following
```
services:
# Setup container that creates folder structure and config files
setup:
image: alpine:latest
container_name: pangolin-setup
volumes:
- ./:/host-setup
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DOMAIN=${DOMAIN:-}
- EMAIL=${EMAIL:-}
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-}
- ADMIN_SUBDOMAIN=${ADMIN_SUBDOMAIN:-pangolin}
- GITHUB_USER=${GITHUB_USER:-oidebrett}
- GITHUB_REPO=${GITHUB_REPO:-getcontextware}
- GITHUB_BRANCH=${GITHUB_BRANCH:-main}
command: |
sh -c "
echo 'πŸš€ Starting Pangolin setup container...'
# Install required tools
apk add --no-cache curl docker-cli openssl
# Validate required environment variables
if [ -z \"$$DOMAIN\" ] || [ -z \"$$EMAIL\" ] || [ -z \"$$ADMIN_PASSWORD\" ]; then
echo '❌ Error: Required environment variables not set!'
echo 'Usage: DOMAIN=example.com [email protected] ADMIN_PASSWORD=mypassword docker compose -f docker-compose-setup.yml up'
echo 'Required variables:'
echo ' DOMAIN - Your domain name (e.g., example.com)'
echo ' EMAIL - Email for Lets Encrypt certificates'
echo ' ADMIN_PASSWORD - Admin password for Pangolin (min 8 chars)'
echo 'Optional variables:'
echo ' ADMIN_SUBDOMAIN - Subdomain for admin portal (default: pangolin)'
exit 1
fi
# Check if config folder already exists
if [ -d \"/host-setup/config\" ]; then
echo '⚠️ Config folder already exists!'
echo 'To avoid overwriting your configuration, setup will not proceed.'
echo 'If you want to run setup again, please remove or rename the existing config folder.'
exit 1
fi
# Validate domain format
if ! echo \"$$DOMAIN\" | grep -E '^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\\.[a-zA-Z]{2,}$$' > /dev/null; then
echo '❌ Error: Invalid domain format'
exit 1
fi
# Validate email format
if ! echo \"$$EMAIL\" | grep -E '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$$' > /dev/null; then
echo '❌ Error: Invalid email format'
exit 1
fi
# Validate password length
if [ $${#ADMIN_PASSWORD} -lt 8 ]; then
echo '❌ Error: Password must be at least 8 characters long'
exit 1
fi
echo 'βœ… Environment variables validated'
# Download container setup script from GitHub
echo 'πŸ“₯ Downloading setup script from GitHub...'
BASE_URL=\"https://raw.githubusercontent.com/$$GITHUB_USER/$$GITHUB_REPO/$$GITHUB_BRANCH\"
if ! curl -fsSL \"$$BASE_URL/container-setup.sh\" -o /container-setup.sh; then
echo '❌ Failed to download setup script from GitHub'
echo 'Make sure the repository exists and is accessible:'
echo \"$$BASE_URL/container-setup.sh\"
exit 1
fi
chmod +x /container-setup.sh
echo 'βœ… Setup script downloaded'
# Run the setup script
echo 'πŸ”§ Running setup script...'
/container-setup.sh
# Create docker-compose.yml for services
echo 'πŸ“ Creating docker-compose.yml for services...'
cat > /host-setup/docker-compose.yml << 'EOF'
services:
# Main Pangolin application
pangolin:
image: fosrl/pangolin:1.5.0
container_name: pangolin
restart: unless-stopped
volumes:
- ./config:/app/config
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
interval: "3s"
timeout: "3s"
retries: 15
# Gerbil WireGuard management
gerbil:
image: fosrl/gerbil:1.0.0
container_name: gerbil
restart: unless-stopped
depends_on:
pangolin:
condition: service_healthy
command:
- --reachableAt=http://gerbil:3003
- --generateAndSaveKeyTo=/var/config/key
- --remoteConfig=http://pangolin:3001/api/v1/gerbil/get-config
- --reportBandwidthTo=http://pangolin:3001/api/v1/gerbil/receive-bandwidth
volumes:
- ./config/:/var/config
cap_add:
- NET_ADMIN
- SYS_MODULE
ports:
- 51820:51820/udp
- 443:443 # Port for traefik because of the network_mode
- 80:80 # Port for traefik because of the network_mode
# Traefik reverse proxy
traefik:
image: traefik:v3.4.0
container_name: traefik
restart: unless-stopped
network_mode: service:gerbil # Ports appear on the gerbil service
depends_on:
pangolin:
condition: service_healthy
command:
- --configFile=/etc/traefik/traefik_config.yml
volumes:
- ./config/traefik:/etc/traefik:ro # Volume to store the Traefik configuration
- ./config/letsencrypt:/letsencrypt # Volume to store the Lets Encrypt certificates
networks:
default:
driver: bridge
name: pangolin
EOF
echo 'βœ… Setup completed! The stack is ready to start.'
echo 'πŸ“Š Start your services with: docker compose up -d'
echo '🌐 Access at: https://'"$$ADMIN_SUBDOMAIN"'.'"$$DOMAIN"
echo 'πŸ‘€ Admin login: admin@'"$$DOMAIN"
# Keep container running briefly to show completion message
sleep 5
"
restart: "no"
```
I then add the environment variables for my pangolin install
```
DOMAIN=example.com
[email protected]
ADMIN_PASSWORD=mypassword
ADMIN_SUBDOMAIN=pangolin
```
Hit Update and Confirm and then select Deploy
You should look in the folder `/etc/komodo/stacks/pangolin-setup` and the pangolin folder will be there
```
/etc/komodo/stacks/pangolin-setup
β”œβ”€β”€ compose.yaml
β”œβ”€β”€ config
β”‚ β”œβ”€β”€ config.yml
β”‚ β”œβ”€β”€ letsencrypt
β”‚ └── traefik
β”‚ β”œβ”€β”€ dynamic_config.yml
β”‚ └── traefik_config.yml
β”œβ”€β”€ DEPLOYMENT_INFO.txt
└── docker-compose.yml
```
5. Now we will start the pangolin stack
Create a new stack called "pangolin-stack"
choose option "file on server"
and select the path
```
/etc/komodo/stacks/pangolin-setup
```
select the file path to be
`docker-compose.yml`
Then deploy the stack. This should start everything correctly and you should see the containers
```
gerbil
komodo-core-1
komodo-ferretdb-1
komodo-postgres-1
pangolin
traefik
```
6. Clean up
You can now destory the pangolin-setup stack as its not needed anymore
7. Secure your komodo install
Now we are going to secure this by adding a pangolin resource for this. We do this by adding a new resource, give it a name like komodo.yourdomain.com
and make sure you make this on the local site. Also set the target to be "komodo-core-1" and port 9120. Leave this resource as a protected resource
with pangolin's authentication
see screenshot of target setup
You should now be able to navigate to https://komodo.yourdomain.com and see the komodo login
8. Make sure you protect the komodo so it cant be accessed directly using the ip address and port
if you already set up a rule to allow port 3456 then deny it
```
sudo ufw delete allow 9120/tcp
```
or, if you dont already have it set up, then deny the port by using
```
sudo ufw deny 9120/tcp
```
then make sure you enable for firewall
```
sudo ufw enable
```
you must also remove the ports from the core docker compose section of the ferretdb.compose.yaml
remove these 2 lines
```
ports:
- "9120:9120"
```
and then use komodo to stop and restart the komodo-core-1 so that the port changes takes effect. When redeployed check that you cant access the komodo portal via the ip/port
```
docker compose -p komodo -f ferretdb.compose.yaml --env-file compose.env down
docker compose -p komodo -f ferretdb.compose.yaml --env-file compose.env up -d --force-recreate
```
```
http://youripaddress:9120
```
9. Extra steps if you installed crowdsec
stop the entire pangolin-stack
you will have previously set up the parameter/variables like this:
```
DOMAIN=example.com
[email protected]
ADMIN_PASSWORD=mypassword
ADMIN_SUBDOMAIN=pangolin
CROWDSEC_ENROLLMENT_KEY=your-key-here
```
cd into `/etc/komodo/stacks/pangolin-setup`
update the docker-compose.yml section for crowdsec and update the ENROLLMENTKEY
change
```
ENROLL_KEY: INSERT-ENROLLMENT-KEY-HERE
```
and go into the shell of the crowdsec container
```
docker run --rm -it \
--name crowdsec-shell \
--entrypoint /bin/sh \
-e GID="1000" \
-e COLLECTIONS="crowdsecurity/traefik crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules" \
-e ENROLL_INSTANCE_NAME="pangolin-crowdsec" \
-e PARSERS="crowdsecurity/whitelists" \
-e ENROLL_KEY="REMOVED" \
-e ACQUIRE_FILES="/var/log/traefik/access.log" \
-e ENROLL_TAGS="docker" \
-v "$(pwd)/config/crowdsec:/etc/crowdsec" \
-v "$(pwd)/config/crowdsec/db:/var/lib/crowdsec/data" \
-v "$(pwd)/config/crowdsec_logs/auth.log:/var/log/auth.log:ro" \
-v "$(pwd)/config/crowdsec_logs/syslog:/var/log/syslog:ro" \
-v "$(pwd)/config/crowdsec_logs:/var/log" \
-v "$(pwd)/config/traefik/logs:/var/log/traefik" \
-v "$(pwd)/config/traefik/conf/captcha.html:/etc/traefik/conf/captcha.html" \
crowdsecurity/crowdsec:latest
```
you can then run
`cscli hub update`
you will see
`Downloading /etc/crowdsec/hub/.index.json`
then Generate the online_api_credentials
You need to regenerate the /etc/crowdsec/online_api_credentials.yaml. The easiest way is rm /etc/crowdsec/online_api_credentials.yaml and register again using the enrolment key from the previous step
```
touch /etc/crowdsec/online_api_credentials.yaml
cscli capi register
cscli console enroll <id>
```
now check that you have all the patterns
ls /etc/crowdsec/patterns/
if you don’t see any folders your crowdsec doesn’t have the required patterns
Here’s a working around to download them
```
wget -P /opt https://github.com/crowdsecurity/crowdsec/archive/refs/tags/v1.6.9-rc2.zip
unzip /opt/v1.6.9-rc2.zip -d /opt
cp -r /opt/crowdsec-1.6.9-rc2/config/patterns/* /etc/crowdsec/patterns/
rm -rf /opt/crowdsec-1.6.9-rc2 /opt/v1.6.9-rc2.zip
```
Everything should be working fine now so restart the pangolin-stack. Check by looking at the logs docker logs crowdsec
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment