This is the first post of my new Astro blog.

Easy hosting with cloudflare and Linux
Serving your own pagepage with cloudflare is easy. Just chose a domain name you like and starting from around 8 $/year you can use it. In my case I registered
juk3.dev
Now you already have the domain where you can host your webpage.
You also have access to all the subdomains, so you can basically create infinite projects, e.g
blog.juk3.dev
or game.juk3.dev.
To serve a webpage owning the domain is only the first step. The second one is to serve the webpage via this domain. There are several ways this can be done.
For dynamic Sites
- Some kind of server
- A Computer you own, which runs more or less 24/7 which is reliably connected to the internet
- A Server / Virtual Private Server (VPS) you rent
For static Sites
- Same as above
- A host like github pages or cloudflare pages
You probably already know that github can store your project files and serve them publically. Instead of serving the “raw” files ‘pages’ serve them as webpages.
This gives you a free version of hosting a webpage.
Find out how here
Static sites are sites where content does not change.
Lets say you visit the wikipedia entry for ‘apple’. You see exactly the same content as someone else visting the same page. This does not mean the article about ‘apple’ can never change, but it only does so when the page is changed on the server. When it does change it changes for everyone.
In contrast a dynamic site shows different content depending on the user and other context
Facebook shows a completely different page depending on who is logged in.
Using your private machine to serve a page
To serve a page content must be delivered to the clients from your server. Your domain can be used to forward people browsing blog.juk3.dev to the IP address of your machine. Your router and machine must allow these requests through open ports.
An easier way is to use a tunnel to cloudflare via cloudflared. This securly connects your machine to cloudflare which sends traffic to your machine and sends back the response similar to a reverse proxy. This frees you of the headache of a ever changing IP address of your machine and also means your machines IP address is not known to the world.
Serving a page via caddy
Serving a page can be done in numerous ways but one very simple solution is caddy which serves static sites over https. Follow the installation guide For my debian system thats
a = 123
def foo():
print(123)
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
Now you have caddy installed it automatically serves all the sites configured in its Caddyfile
the Caddyfile can written anywhere but after the install there ist one at
/etc/caddy/Caddyfile
if you read the content from Caddyfile you ll see how the configuration is done
:80 {
# Set this path to your site's directory.
root * /usr/share/caddy
# Enable the static file server.
file_server
# Another common task is to set up a reverse proxy:
# reverse_proxy localhost:8080
# Or serve a PHP site through php-fpm:
# php_fastcgi localhost:9000
}
the root of /usr/share/caddy is exposed on port 80, so on
<localhost:80> you can see the served site from caddy (:80 is the default port and can be skipped)
I added
import /etc/caddy/*.caddy
this allows creating a single file for each caddy instance.
I add a file
:MYPORT {
root * /srv/MYSITE
file_server
}
and now all content from MYSITE is served via <localhost:MYPORT>
Easy!
Right now the page can not be visited from outside your network. When your inside the same network you can request the same site via ip. On the hosting machine call
ip addr show
and search for an address like **192.168.178.XXX ** . This is your local ip address and other machines from the network can visit your page via
<192.168.178.XXX:80>
[!NOTE] This is more difficult if you host via wsl, since the wsl port has to be connected with the host windows machine port. There are workarounds floating around, but its kinda annoying see: github and a write up of the methods https://iangge.github.io/posts/port-forwarding-between-windows-and-wsl2/
Making the page available
The outside world can not access your page right now, since your router and firewall don’t allow outside requests reaching your machine. You could open some ports on your router, modify the firewall accordingly and find out what your (most likely) dynamic ip address is and tell your Registrar (cloudflare in my case) to forward traffic to my ip. This would need updating everytime my ip changes, and also be risky since it would expose my IP to the world. A better solution would be to have a reverse proxy in the middle which forwards traffic to my machine, but this would mean extra infrastructure, and still not solve the issue of a dynamic ip. Luckily cloudflare has a solution for this. That is also the reason why I started the endeavor in the first place. Its called cloudflared and works like this. Request to my site go to cloudflare instead. A tunnel forwards those towards my served sites. The tunnel has to be build from the server/hosting machine. The outside world does not know my IP address and cloudflare can run some security features on the requests as well. And how is it setup?
Follow the install instructions here
# Add cloudflare gpg key
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
# Add this repo to your apt repositories
# Stable
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
# Nightly
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://next.pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
# install cloudflared
sudo apt-get update && sudo apt-get install cloudflared
Connect cloudflare with your host via certificate
now that its running it needs some setup.
First cloudflared has to connect with your cloudflare account.
cloudflared tunnel login
Login to cloudflare and select the domain you want to use the tunnel for.
After authorizing a cert.pem is created in ~/.cloudflared or /root/.cloudflared/
or via the cloudflare interface. Here you can generate a tunnel via Protect & Connect -> Networking -> Tunnels
Create your tunnel
cloudflared tunnel create test_tunnel
creates a test_tunnel which can be referenced by this name. It also creates a certificate at ~/.cloudflared/<UUID>.json
this is the secret for your tunnel
setup a dns record to route to your domain cloudflared tunnel route dns test_tunnel test.juk3.dev
let dns know to forward traffic from test.juk3.dev to the created tunnel and not run the tunnel. it still needs a small configuration yml `config.yml tunnel: test_tunnel credentials-file: ~/.cloudflared/<UUID>.json
ingress:
- hostname: test.juk3.dev service: http://localhost:8080
- hostname: gitlab-ssh.widgetcorp.tech service: ssh://localhost:22
- service: http_status:404 ` this config can sit anywhere. the default location is ~/.cloudflared
now run the tunnel through cloudlflared tunnel –config <PATH TO CONFIG> run test_tunnel
These are called locally managed tunnels <https://developers.cloudflare.com/tunnel/advanced/local-management/\> cloudflare recommends using remotely-managed tunnels, where the confiugration is stored on cloudflare and not locally infos to setup a remote tunnel can be found here <https://developers.cloudflare.com/tunnel/setup/\>
the same setup works for django too, just remember to runserver with 0.0.0.0:PORT so its listening to all connections.
Caddy already auto starts via systemctl, but cloudflared doesnt. since we want to use both in conjuction we run
sudo cloudflared --config /path/to/config.yml service install --config is optional
cloudflared will create a directory at /etc/cloudflared/ containing the config
when running the command again, it will be confused which one to use.
In the best case you only have to run the command once. I had quite some issues though.
In the end “sudo” was the culprit together with a malformed ingress.
To avoid these issues make sure to give absolute paths to your config and to your crendentials file,
so.
To recognize malformed config files its better to run the command not as service but plainly, e.g.
sudo cloudflared --config /path/to/config.yml run test_tunnel
this way the output will show you errors.
The logs which should have been generated by the service /systemctl into journalctl did not show any proper error messages for some reason.
Static hosting
Last but not least cloudflare allows direct hosting of static pages, similar to github.pages The feature is kinda hidden in a foot note when creating a ‘Worker or Pages’. To me it seems like cloudflare does not want anyone to use the pages feature but it still works in August 2026. Just link your resources, a github repo in my case, add the build command (“npm run build” in my astro case) and tell github where the build output will turn up (‘/dist’ in my case). Cloudflare will publish the site under <SomeName>.pages.dev via cloudflare you can set a custom domain for this page, which adds the proper dns register to use your domain. Before I did that I tried adding the dns register myself, but it did not work for some reason. In my mind it should have been simply adding the url e.g. blog.juk3.dev as cname pointing it towards <SomeName>.pages.dev. This is also exactly what happen after rerouting the Page via the cloudflare feature, so I dont know why it did not work before.
Astro
For this simple blog, Im trying out ‘Astro’. I have the most experience with python on a django/htmx/alpinejs/tailwindcss/js stack but for a blog this seems overkill. Since im the only one writing here, a CMS like wagtail is overkill too, although it could have been an interesting learning experience. For the blog I basically want to only create some static files, with some templating. Your favorite ChatBot recommended Astro, so here I am trying it. I try to follow the Astro tutorial more closely then I did for the cloudflare setup, and will use less ai. I feel like the documentation for most well developed tools beats the quick ai setup, which tends to break at some point and also reduce learning effects.
Installation
I followed the installation guide from here
https://docs.astro.build/en/install-and-setup/
install astro via npm
npm create astro@latest
I chose the option to start with a blog setup
build the static pages via
npm run build
and preview these build artifacts with
npm run preview
run the dev server using, which shows you the dynamically generated content with hot reload
npm run dev