Secure Website Hosting Without Open Ports: Cloudflare Tunnel & Kamal-deploy
Hosting a website traditionally involves exposing certain ports ( 80, 443, ...) to the public internet. However, this approach often brings security risk, such as DDoS attacks and unauthorized access attempts. Or, simply put, there may be other reasons why you don’t want or can’t expose ports to the internet.
In this post, I’ll guide you through an alternative method to host your website securely without opening 80/443 ports. We’ll be using Cloudflare Tunnel, a service that connects your server to Cloudflare’s network securely, and Kamal-deploy, a deployment tool that simplifies the process of managing applications. By the end, you’ll have a fully deployed, secure website that doesn’t rely on open ports.
Let consider the diagram below first:
Components
Cloudflare Tunnel is the key component in this setup. It creates a secure tunnel that allows public access to your web service without the need to open any ports.
Kamal-deploy simplifies the deployment process, allowing you to deploy applications to any Linux server in just a few minutes. It automates key tasks such as pulling code, building and running containers, and managing environment variables, networking, and SSL certificates.
Prerequisite
- A domain configurate to manage on Cloudflare, you can follow the guide here
- A linux server that pre-setup docker and allow to access from your local machine
- Kamal already install on your project (assume that a Rails project, but you can use with any application that can be containerized.
Setup a Cloudflare tunnel
Setup an tunnel to your linux server, follow the official guide from Cloudflare https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/
Copy full token and put in in safeplace, we'll use it to config on kamal
then, add new tunnel config to map domain into this tunnel.
Setup Kamal Deploy & Config application
the content of deploy.yml as the code bellow:
In this Kamal deployment configuration, the Cloudflared Docker container is set up as an accessory of Kamal and connected to an external Docker network named "pff". This explains why, in the earlier tunnel configuration, we were able to point the domain to traefik:80.
If you don’t use an external network configuration, you would need to expose the Traefik port and change the tunnel config to point the domain to host_ip:<traefik_host_port>
Config the tunnel token in .env.rb
Config/environments/production.rb
Update assume_ssl = true && force_ssl = false to allow application can access with Cloudflare SSL/TLS Flexible mode, ssl terminating buy Cloudflare/& Cloudlfare tunnel
# Assume all access to the app is happening through a SSL-terminating reverse proxy.
# Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
config.assume_ssl = true
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = false
Deploy with kamal
kamal envify
kamal env push
kamal traefik boot
kamal accessory boot cloudflared
kamal deploy
kamal traefik reboot -y
Output
Here’s my hobby project: hosting on my local miniPC (Asus x300) using Cloudflare Tunnel:: https://miningboard.com/