To see what's happening in docker, we have Docker Desktop. But what if your VPS runs docker, do we have a GUI for that ? So I recently set up Portainer on my Ubuntu VPS to manage Docker containers through a web-based interface. Instead of exposing the Portainer dashboard directly to the public internet, I decided to access it through an SSH tunnel.

Here's a quick walkthrough of how I got it working.

1. Running Portainer as a Docker Container

The first step was to make sure Docker was installed and running on my Ubuntu VPS.

Once that was ready, I pulled and started the Portainer Community Edition container:

docker volume create portainer_data docker run -d \ -p 127.0.0.1:9443:9443 \ --name portainer \ --restart=always \ -v /var/run/docker.sock:/var/run/docker.sock \ -v portainer_data:/data \ portainer/portainer-ce:latest 

A quick breakdown:

  • 127.0.0.1:9443:9443 exposes Portainer's HTTPS interface on port 9443 only locally on the vps (not publicly accessible).
  • /var/run/docker.sock allows Portainer to communicate with the Docker engine.
  • portainer_data stores Portainer's configuration and data persistently.
  • --restart=always ensures the container starts automatically when the VPS restarts.

2. Copying the setup token

After the container was running, I needed to complete Portainer's initial setup.

Portainer generates a setup token that can be retrieved from the container logs:

docker logs portainer 

I copied the setup token and used it during the initial setup process in further steps.

3. Creating an SSH Tunnel

This is where things get interesting.

Instead of opening port 9443 to the entire internet, I created an SSH tunnel from my local machine to the VPS.

On my local machine, I

ssh -L 9444:localhost:9443 username@YOUR_VPS_IP 

Here's what this command does:

  • -L creates a local port forwarding tunnel.
  • The first 9444 is the port on my local machine (I didn't choose 9443 because my local Portainer listens on it).
  • localhost:9443 is the destination port on the VPS.
  • username@YOUR_VPS_IP connects to my VPS over SSH.

Keep this SSH session running in the background of your terminal.

Now, whenever I want to access Portainer, I simply open the following URL in my local browser:

https://localhost:9443 

And that's it! I'm now accessing the Portainer dashboard running on my remote Ubuntu VPS, directly from my local machine.

But wait, the setup isn't over yet.

One thing worth noting is that Portainer's web interface listens on port 9443 using HTTPS by default.

So, accessing it using:

http://YOUR_VPS_IP:9443 

won't work as expected.

The correct URL is:

https://YOUR_VPS_IP:9443 

Since I'm accessing it through SSH tunnelling, I don't need to expose the dashboard publicly.

4. First time setup

When you access the portainer dashboard for the first time, it will ask you to create a user (admin by default) and a password. 

Setup a secure password and paste the setup_token that we copied in step 2.

A small but important tip: Save this password in a password manager like Bitwarden. It's much better than storing it in a text file or relying on memory.

Why I Prefer This Approach

I like this setup because I don't have to expose another administrative dashboard to the public internet.

  • Portainer runs inside a Docker container on my VPS.
  • Its dashboard is accessible through an SSH tunnel.
  • I don't need to make port 9443 publicly accessible.
  • I can use my existing SSH access to securely reach the dashboard.

One security note: Make sure port 9443 is blocked from public access in your VPS firewall or cloud firewall. The Docker port mapping can expose a port independently of some UFW rules, so verify the actual network accessibility rather than relying on UFW alone.

Also, remember that mounting /var/run/docker.sock gives Portainer extensive control over Docker on the VPS, so keep its administrator credentials secure.

That's how I got Portainer running on my Ubuntu VPS and accessed it locally without making its dashboard publicly accessible. A simple combination of Docker, Portainer, and SSH tunnelling!