Introduction
Have you ever wanted to share one of your self-hosted services with an in-person or online friend, but you'd rather not attach it all to your home network or expose ports on your home router? This can be achieved pretty handily with a VPS, Pangolin, and Crowdsec. If you're not familiar with these projects, better to hear it from them than me: Pangolin CrowdSec
Step 1: Your VPS
Before we can get started installing anything, we need a virtual machine rented in a datacenter somewhere. This is going to act as our "face", accessible from the open internet. For mine, I've decided to go with RackNerd, which are very affordable and easy to use. Regardless of what you go with, follow the Pangolin docs regarding VPS system specs. If you go with RackNerd, Pangolin has referral links on that same docpage that help support the project at no cost to you. I went with the RackNerd Basic Plan, including 2vCPU, 2GB RAM and a 30GB SSD. If you're following this guide to the letter, we'll be using Ubuntu 22.04 as our OS.
Step 2: Your DNS
We are also going to need a domain name. I like to purchase mine from NameCheap
because I don't really care about a fancy TLD, I like to go for the cheap stuff like .xyz, .pw, .casa, but really anything will do. The only thing to watch out for with NameCheap is they love to do a steep discount on one year, but make sure to check and make sure the renewal fees aren't going to be astronomically higher than your first year (unless you want to be dealing with changing domains regularly).
Once you've purchased/selected the domain you'll be using, go to your DNS settings for your domain (in NameCheap's dashboard this is called "advanced DNS") and add two A records:
- For the first, put the host as "*" and have the value be the public IP address of your VPS.
- For the second, put the host as "@" and the value be the public IP address of your VPS.
Step 3: Firewall
Okay there is one more thing we have to do before we can start installing things, and this is set up our firewall. This can be done manually with iptables/nftables, but I am lazy and we are using Ubuntu so this guide will be using Uncomplicated FireWall (UFW). First, before enabling the firewall, allow SSH connections through so you won't have to rescue yourself through the VPS dashboard:
sudo ufw allow OpenSSH
This will make sure that your SSH connections can get through. Next, we're going to add the necessary ports for pangolin:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 51820/udp
sudo ufw allow 21820/udp
Once you're sure that you have added all the necessary ports, start up the firewall with:
sudo ufw enable
Step 4: Installation
Connect to your VPS via SSH and download the pangolin installer. There are other ways, but this is quick, easy, and all in shell:
curl -fsSL https://digpangolin.com/get-installer.sh | bash
The next step is to run the installer, but as with any random shell script you download from the internet I recommend taking a look at it first. But it does what it says on the tin.
sudo ./installer
It's going to give you a few prompts to follow:
- Base Domain: This should be your domain without any subdomains attached. For example, "example.com"
- Dashboard Domain: You can just press enter and it will set your dashboard to the "pangolin" subdomain (pangolin.example.com)
- Let's Encrypt Email: This will be both the email your SSL certs are signed with as well as your admin login email
- Tunneling: You'll want to hit "Yes" for this, as this is mainly what we're using Pangolin for, but if you select "No" the setup will work fine as a standard reverse proxy.
- Configure Email: Pangolin can be set up so you need a cookie from signing in to Pangolin to access specific subdomains. An email server can be configured to send system emails for your pangolin install, but for the scope of this guide this will not be included as it is not necessary for home use. You can select "No"
- Confirm Installation: The script will prompt you to confirm the install and starting of 3 docker images (pangolin, gerbil, traefik). If you do not have docker installed, it will also offer to do this for you. There is also an option to choose "docker" or "podman" for your containerization system. I'm more familiar with Docker, so that is what we will be using.
- Install CrowdSec: Select Yes, and confirm that you are willing to manage CrowdSec's configuration. This will set up a basic CrowdSec install to
You should get a message saying your installation is complete, and a link directing you to set up your pangolin instance's admin account.
After all this, you should have 4 docker containers running: pangolin, gerbil, traefik, and crowdsec. This can be confirmed using the command:
docker ps -s
Step 5: Pangolin Configuration
Now we need to configure our Pangolin instance, this will be at:
https://example.com/auth/inital-setup
Note: If you opened the initial setup page immediately after finishing the installation, you may get an insecure connection warning. This is only because the Let's Encrypt certs have not propagated yet, you can either proceed anyways or just wait a few minutes then refresh and your connection will be properly secured.
Enter your admin email address, set a good password.
You'll be prompted to create an organization. This can be named whatever you like, it does not matter.
The important next step is to set up our first "site", or location that our Pangolin instance will tunnel to. Navigate to "Sites" and hit "Create Site". This can be named whatever you like, once again it does not matter and is only for your own reference. The site address will be pre-filled out for you, and I don't recommend touching it unless you really know what you're doing.
For the Tunnel Type, we'll be using a Newt tunnel. This works almost identically to a cloudflare tunnel if you are familiar with those, but selfhosted. Under "Install Newt", you have a number of selections based on the operating system you are trying to tunnel to. Because I use a docker stack on my home server, that's what we'll be covering. Similarly to a cloudflare tunnel, all we need to do is make a quick docker-compose. It can be copied, keys and all, in that "Install Newt" section once Docker is selected. You can leave the box regarding "Accept Client Connections" unchecked, as it is not necessary for this use case. It should look something like this:
services:
newt:
image: fosrl/newt
container_name: newt
restart: unless-stopped
environment:
- PANGOLIN_ENDPOINT=https://pangolin.example.com
- NEWT_ID=generated_by_pangolin
- NEWT_SECRET=generated_by_pangolin
Once you have copied it all over, hit the orange "Create Site" button at the very bottom of the page, and start your newt container using your docker UI (dockge/portainer) or using docker-compose up -d
.
If you've created the site and started your container, after a minute or two you should see your site showing as "Online" in your Pangolin dashboard.
Now you can navigate down to the "Resources" section in the left sidebar, and start adding subdomains. For an example, we make a resource named "jellyfin", select "HTTPS Resource". For our subdomain we use "jellyfin.example.com" Under "Targets Configuration", you can leave it as http, set the IP address as the LAN IP of your home machine (or the docker IP if you want to be slightly more secure, I'll admit I'm a little lazy here), and then for port we would use our Jellyfin webUI port, 8096. Hit save.
Now, you'll be taken to a settings page for the resource we've just created. By default, a new resource is only accessible after authentication and with possession of a Pangolin access cookie. If a cookie is not possessed, it will redirect you to a login page for your Pangolin instance before putting you through to the requested resource. If you would like your resource to be accessible without Pangolin authentication (for example, Jellyfin, as it has it's own authentication system), navigate over to the "Authentication" tab and turn off "Use Platform SSO" then hit "Save Users and Roles" to save the changes.
After all that, your tunnel is ready! You should be able to connect to your resource at home using the address "jellyfin.example.com" and you can sign in and stream/use your resource as normal!
Further configuration of CrowdSec for additional security
If you've been following this guide closely, as it stands right now only the connections routed through our Traefik container are being covered by the CrowdSec bouncer installed by the Pangolin installer. Our SSH port that we opened in our firewall is not protected by any bouncer, and so for added security we can add one now.
If you are using the same Ubuntu version that I am (22.04) then your operating system will be using nftables, so we will be installing the nftables version of the bouncer.
sudo apt install crowdsec-firewall-bouncer-nftables
Next, we'll need to create an API key to link our new bouncer to our existing crowdsec install.
docker exec -it crowdsec cscli bouncers add vps-firewall
You will be given an api key, make sure to copy this somewhere you can retrieve it in a minute. You'll want to copy the API key into your bouncer's configuration file. Open it with your preferred text editor, if you haven't installed any we can use nano.
nano /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml
Once inside, you will want to paste in the API key we just generated. Additionally, we need to set the IP address that the bouncer tries to connect to with that API key. This will be your docker IP address for the container. If you are not sure of the IP address, use this command:
docker inspect crowdsec
If you scroll towards the bottom of that output, you should see an "IP address" field that tells you the IP address of your container. Now, in our crowdsec-firewall-bouncer.yaml we can set it to that IP, as an example:
api_url: http://192.168.160.3:8080
Now, go to your docker-compose.yml that was generated by the Pangolin installer. If you didn't cd into a specific directory before running the script, this is likely in your VPS's home directory. Edit this, and expose the port necessary for local API access:
service:
crowdsec:
ports:
- 6060:6060 # Metrics port
- 8080:8080 # Local API port
Stop all your containers with docker stop -a
, then start them again using docker-compose up -d
. Now that the docker container is ready for the API to connect, we can restart the bouncer.
systemctl restart crowdsec-firewall-bouncer
And it should be running! To verify that it has all connected properly, run the command:
docker exec crowdsec cscli metrics
and you should get an output along the lines of
+------------------------------------------------------------------+
| Local API Bouncers Metrics |
+---------------------------+----------------------+--------+------+
| Bouncer | Route | Method | Hits |
+---------------------------+----------------------+--------+------+
| traefik-bouncer | /v1/decisions/stream | HEAD | 2 |
| traefik-bouncer@10.0.4.20 | /v1/decisions | GET | 3 |
| vps-firewall | /v1/decisions/stream | GET | 84 | <---------
+---------------------------+----------------------+--------+------+
Now you've got your SSH port protected by CrowdSec as well.
CrowdSec Console
This last step is entirely optional, and is only if you would like to get some additional control over your CrowdSec install. The features involved are:
- A fancy dashboard through which you can view stats on IPs your bouncers have blocked, decisions they have made, etc.
- The ability to subscribe to blocklists (warning, many of these are paid, though there are some good free ones)
There are likely others, but these are the ones I'd imagine you are likely to care about.
The first step is signing up, as you need an account with CrowdSec's website to access CrowdSec console (boo, I know.) Create an account there, and once signed in navigate to Security Engines -> Installation. Because our crowdsec install is in Docker, select "Docker" as the platform then scroll down to Step 3, "Connect with the Console". You'll want to copy the command, but we're going to have to modify it to exec through docker instead as I found the base command they give you is the same as it would be for a native install and did not work properly.
docker exec -it crowdsec cscli console enroll -e context code_copied_from_crowdsec_page
You should get some output marking your success, and you can now go to your Engines page and you should see a prompt at the top waiting for you to approve the connection/enrollment. Once enrolled, if you wait a few minutes you'll be able to look at the Alerts, Engines, Decisions, and Remediation metrics of your CrowdSec install.
Additionally, you can now subscribe to additional blocklists outside of the standard community lists. Unfortunately, many of these blocklists are curated by CrowdSec themselves as part of their enterprise offers, so to see ones you can subscribe to with your community install go to Blocklists -> Search -> Select "Free" tier checkbox in the left column. You can subscribe up to 3 on your free community license, and can help bolster your Community Blocklist that CrowdSec comes with.
Thanks for reading! I hope this helped you getting started with Pangolin and Crowdsec, and enjoy fast remote access to your server without involving Cloudflare or exposing your home IP. If you have any questions, feel free to drop me a message on Signal (IYKYK) or contact me at cenotaph.contact@pm.me