Compare commits
4 Commits
dev
...
877fc6bebf
Author | SHA1 | Date | |
---|---|---|---|
877fc6bebf | |||
8901288b93 | |||
d16c6dac1c | |||
ee8e9def4f |
11
README.md
11
README.md
@ -13,21 +13,12 @@ docker run --rm -it -p 8080:8080 wip hugo serve --bind 0.0.0.0 --port 8080
|
||||
### Opinion Pieces
|
||||
- [ ] Clean Architecture is stupid - dependency injection is king
|
||||
- [ ] Neorg is bad, actually - ?? is king
|
||||
- [ ] Clean Architecture is stupid and overly complicated - dependency injection is king
|
||||
- [ ] For want of a neater (human) internet
|
||||
- [ ] A truly FOSS printer.
|
||||
even the hardware should be FOSS. - most parts should be 3d printable.
|
||||
should be a laser printer, as inkjet is stupid.
|
||||
- [ ] A truly FOSS eink reader.
|
||||
- [ ] VIM Bindings everywhere please
|
||||
- [ ] trying to use a MIDI controller as a piano on Linux is insanity
|
||||
|
||||
### Digital Soverignty
|
||||
- [x] how to host a blog
|
||||
- [ ] how to securely "self-host" using a VPS, portainer and traefik
|
||||
- [x] how to configure neomutt
|
||||
- [ ] how to configure neomutt
|
||||
- [ ] how to securely host a mail server
|
||||
- [ ] how to private tracker with a NAS
|
||||
|
||||
### Old sillyblog
|
||||
- [x] Avr memory model
|
||||
|
@ -3,10 +3,10 @@ title: About gtz blog
|
||||
author: Asger Gitz-Johansen
|
||||
---
|
||||
|
||||
I am a software engineer from Denmark working at [GomSpace](https://gomspace.com/home.aspx). This is just my simple
|
||||
blog that I use for letting out "blogging-steam". I write GNU/Linux based tutorials and sometimes I write opinion
|
||||
pieces. These posts are mostly for my own sake, but I hope you find my stuff useful.
|
||||
|
||||
I am a software engineer from Denmark working at [GomSpace](https://gomspace.com/home.aspx).
|
||||
This is just my simple blog that I use for letting out "blogging-steam".
|
||||
I write GNU/Linux based tutorials and sometimes I write opinion pieces.
|
||||
I hope you find my stuff useful.
|
||||
If you want more from me, check my links:
|
||||
|
||||
- [GitHub](https://github.com/sillydan1)
|
||||
|
@ -69,7 +69,7 @@ gdb: > x/16xb my_heap_object
|
||||
```
|
||||
|
||||
The first bytes at address `0x800100` are `0a` and `00`. These bytes are the *free-list* entry and explains how "big"
|
||||
the object is. When reading this, we have to remember that the model is little endian-based (meaning that the bytes are
|
||||
the object is. When reading this, we have to remember that the model is littleengine-based (meaning that the bytes are
|
||||
switched),
|
||||
so we actually have the value of `0x000a`, meaning `10` in decimal. This makes a lot of sense, since we allocated 5
|
||||
`int`s, that is of size 2 (16bit integers).
|
||||
|
@ -1,90 +0,0 @@
|
||||
+++
|
||||
date = '2018-05-10'
|
||||
draft = false
|
||||
title = 'Computation in Nature'
|
||||
tags = ['philosophy', 'old']
|
||||
categories = ['opinion']
|
||||
+++
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This was written as a student project as part of our ethics course, where we had to write an opinion piece on anything
|
||||
we wanted in the field of computer science. Note that this was before *LLM*'s was a thing. I also apologize if the
|
||||
wording is off - this was written in an afternoon as a rush-job. I still think it's an interesting read though.
|
||||
|
||||
# Computation in Nature
|
||||
|
||||
> "If you ever think your code is bad, just remember that CPUs are just rocks that we tricked into thinking"
|
||||
|
||||
**Does nature compute, or is computation something that only humans are doing? If so, what is it about?**
|
||||
|
||||
To answer this question, we would need to define what the terms used in it even means. If you look up the definition
|
||||
of the word ’compute’ on Merriam Websters dictionary, you find that it primarily means _"to determine
|
||||
especially by mathematical means"_. This definition mentions a usage of mathematics, which suggests a close bond
|
||||
between these concepts. What would it mean to determine something? I would argue that it means to make a decision
|
||||
based on either prior experience, data or calculations. This implies that computation have a focus on deciding
|
||||
and _"finishing a thought"_. It has an end goal. You can even use conclusions made by previous computations to
|
||||
compute more advanced problems.
|
||||
|
||||
In other words, computation is about answering queries about data and the process of doing so. We see
|
||||
mathematics emerge in nature aswell. In
|
||||
[The Chemical Basis of Morphogenesis](https://www.dna.caltech.edu/courses/cs191/paperscs191/turing.pdf), Alan M. Turing
|
||||
mentions that flower petals rarely exceeds a quantity of five. We even see the fibonacci sequence in [sunflower
|
||||
seeds](http://popmath.org.uk/rpamaths/rpampages/sunflower.html).
|
||||
|
||||
An example of computation in nature is actually very easy to find. Take a rabbit, or any other smaller prey. A rabbit
|
||||
is constantly observing and reacting to the sorrounding environment, otherwise it gets eaten by predators or fall
|
||||
into a lake and drown or any other scenario involving death. You could argue that the rabbit is constantly asking
|
||||
questions about what to: _"Should I run away?"_, _"Should I keep eating?"_, _"Should I be eating this?"_ etc. The
|
||||
rabbit may not be consciously aware of these queries, but nevertheless, it is answering to them through actions.
|
||||
|
||||
In Empiricism, the concept of a mind being a blank slate (in this case we are talking about a human mind, not
|
||||
a rabbit’s), which remembers experiences throughout it's life is very much applicable here. This trait means that a
|
||||
human mind has a memory, i.e. It can remember old conclusions and recall them when desired. We can actually prove that
|
||||
this trait is not exclusive to humans, since we can observe other mammals (and even fish and reptiles) demonstrating
|
||||
the usage of memory. A prime example is the elephant, but pretty much any animal applies here.
|
||||
|
||||
In Rationalism, we see a similar pattern that mimics memory - using the method of deduction to find conclusions and
|
||||
deduct new conclusions. However, if you were to believe the Rationalists, getting the data needed for computation
|
||||
in nature, may be a tricky task. We previously had an assumption that we could trust our senses and that other
|
||||
creatures also had senses. In Rationalism the only thing we can trust is the fact that we are doubting. Since we
|
||||
can’t say anything about if the rabbit is doubting everything. This is where the rabbit example breaks down a
|
||||
little, but we are not completely stuck here. Humans are mammals and mammals are a type of animal. Animals are
|
||||
part of nature, therefore humans must be part of nature. You and I are humans (I assume) and this logic enables us
|
||||
to make deductive arguments based on subjective thoughts. The first part of the Cartesian circle, _"Dubito ergo
|
||||
cogito"_ (_"I doubt, therefore I think"_) made by René Descartes, is actually very applicable to computation in
|
||||
nature. Thinking is a form of computation and since _I_ am part of nature. Computation rationally happens in nature.
|
||||
|
||||
But what about non-natural computation? Artificial computation machines such as modern digital computers or even
|
||||
old mechanical adding-machines are definitely things that compute data. There is a diconnect from artificial
|
||||
computers to natural computers (brains) though. Currently humans have not been able to produce a machine with natural
|
||||
intuition as we observe it in nature. We have come close to something that looks like it with simulated organisms,
|
||||
but we are not even close to the complexeties of an intuitive brain such as the human one (or even other clever
|
||||
mammals, such as the dolphin or chimp). I personally believe that the reason for this disconnect is because of
|
||||
the intention of the computational device at the point of origin. The intent that biology had when brains were
|
||||
invented was certainly not to fix mathematical problems. It was primarily for the organism to survive and have a
|
||||
better chance for survival. But fixing mathematical problems is the exact intent humans had when we created our
|
||||
artificial computers. This **intent** changes the very nature of the system, and because of this, even though brains
|
||||
and computers might be similar in some ways they are and always will be fundamentally different things.
|
||||
|
||||
A. M. Turing presents (and disagrees with) various arguments, in his article
|
||||
[Computing Machinery and Intelligence](https://archive.org/details/MIND--COMPUTING-MACHINERY-AND-INTELLIGENCE),
|
||||
that a computer will not be able to be conscious. I tend to follow Turings idea that most of the arguments he
|
||||
presents are either made out of a tendency towards thinking that humans have to be superior to machines, either
|
||||
intellectually or that we can *feel* things. I do disagree with one point that he makes in the article: Turing
|
||||
argues that a computer/program will never be able to change it’s behavior based off of prior experiences, which
|
||||
sounds ludicrous if you’ve taken any modern Machine Intelligence class. This was probably a conclusion he came
|
||||
to because of the time era he was in and that AI as a field was not as big (if at all existent) at the time.
|
||||
|
||||
Turing finishes the article with the notion that there is still a lot of work to be done in the field of AI and it
|
||||
is a fun contrast to see what arguments and thoughts a mind like his had back in the fifties, compared to modern
|
||||
AI can offer. Will humans ever be able to create a truly conscious artificial mind? And will we ever be able to
|
||||
test it properly?
|
||||
|
||||
If you believe the Mathematical Realists, mathematics is a thing that exists independently of humans, and can be
|
||||
found/discovered by any being clever enough to deduct these laws. This point of view can be very reassuring, if
|
||||
you believe that real artificial intelligence can be made. Since mathematics is an inherit trait of the universe,
|
||||
and that computers are machines that can (essentially) execute math, and that humans are part of nature. It might
|
||||
be possible to make an AI that is (atleast) as clever as humans, maybe it is innevitable.
|
||||
|
||||
{{< centered image="/6616144.png" >}}
|
@ -1,210 +0,0 @@
|
||||
+++
|
||||
date = '2025-04-15'
|
||||
draft = true
|
||||
title = "How to Set Up Crowdsec"
|
||||
tags = ["howto", "tutorial", "web", "securoty"]
|
||||
categories = ["technical"]
|
||||
+++
|
||||
## Crowdsec
|
||||
|
||||
> NOTE: This configuration blocks *many* varieties of clients and services. You might want to whitelist your own ISP and
|
||||
> / or your own IP ranges (perhaps even your entire country if you're trusting enough) in case your own services and
|
||||
> homebrew experiments gets banned.
|
||||
|
||||
Short for [crowdsecurity](https://www.crowdsec.net/), crowdsec is a community effort to bring auto-banning security to
|
||||
the masses, and it's surprisingly easy to set up. You just have to understand how the thing works.
|
||||
|
||||
|
||||
I noticed that I am getting a lot of suspicious traffic on my gitea instance. Usernames such as `log4j` and `thomad`
|
||||
from china and bulgaria. Yea. Let's enable some fucking security.
|
||||
Fuck I hate that I have to do this, but I guess people will be assholes.
|
||||
|
||||
After [this](https://www.youtube.com/watch?v=-GxUP6bNxF0), the banhammer came down with the might of zeus. Now no-one
|
||||
gets access. Not even me. I tried to do some country-code whitelisting, but that was a bit of a dud. I'm tired now.
|
||||
Will look at it tomorrow.
|
||||
|
||||
Okay! I seem to have it working now! That was an adventure. Will elaborate when I get back home.
|
||||
|
||||
Okay, There's multiple "things" to a crowdsec setup. Crowdsec (the non-paid cloud solution) consists of:
|
||||
- The core crowdsec security engine (`crowdsecurity/crowdsec` container image)
|
||||
- Does the "detection" and hardcore logic and makes decisions.
|
||||
- The bouncer (`fbonalair/traefik-crowdsec-bouncer:latest` container image in my case)
|
||||
- Enforces the decisions.
|
||||
- There are multiple different "types" of bouncers. I just use the forwardAuth type, as that is the most straight
|
||||
forward one. Especially when combined with traefik.
|
||||
|
||||
### Concepts
|
||||
|
||||
In short, there are only a couple of concepts you should know in order to *use* crowdsec. This is
|
||||
Feel free to skip these if you
|
||||
don't care for now, and just want something up and running.
|
||||
|
||||
- Acquisitions
|
||||
- In order for `crowdsec` to know *what* and *where* to look for potential intruders, threats etc. You must tell it
|
||||
in the form of *acquisition* configurations. The easiest thing to do is to just give `crowdsec` access to your docker
|
||||
logs and traefik logs - this is excactly what we're aiming to do.
|
||||
- Parsers
|
||||
- Bucket Overflow
|
||||
- Bouncers
|
||||
|
||||
Note that the core crowdsec security engine should be part of the core traefik/portainer deployment because it will
|
||||
need some elevated privileges. The traefik service should also register some middlewares, so it can't be part of the
|
||||
portainer managed containers / stacks.
|
||||
|
||||
When using Traefik, make sure to add the docker labels that enable traefik trafficing to the containers:
|
||||
|
||||
```yaml
|
||||
# For the new containers.
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=proxy
|
||||
- traefik.http.routers.traefik-bouncer.entrypoints=websecure
|
||||
```
|
||||
|
||||
## "easy"
|
||||
|
||||
|
||||
This shit was not easy to set up. But it is easy to maintain. Keep a "new"/"learning" mind, and all should be fine.
|
||||
|
||||
## Configuring the Bouncer
|
||||
|
||||
Also called "Remediation"
|
||||
I am using the traefik bouncer, that is using
|
||||
[forwardAuth](https://doc.traefik.io/traefik/middlewares/http/forwardauth/) to check if an IP is blocked or not.
|
||||
|
||||
Configure the container in docker compose and afterwards, you should introduce the traefik middleware in the dynamic
|
||||
and static configuration, like so:
|
||||
|
||||
```yaml
|
||||
# dynamic traefik config
|
||||
http:
|
||||
middlewares:
|
||||
traefikBouncer:
|
||||
forwardauth:
|
||||
address: http://traefik-bouncer:8080/api/v1/forwardAuth
|
||||
trustForwardHeader: true
|
||||
```
|
||||
|
||||
```yaml
|
||||
# static traefik config
|
||||
entryPoints:
|
||||
http:
|
||||
address: ":80"
|
||||
http:
|
||||
middlewares:
|
||||
- traefikBouncer@file
|
||||
https:
|
||||
address: ":443"
|
||||
http:
|
||||
middlewares:
|
||||
- traefikBouncer@file
|
||||
```
|
||||
|
||||
If you have (I do) some other names for the `address: ":443"` and `":80"` middlewares, don worry, just add the
|
||||
`traefikBouncer@file` to the list of middlewares and you should be good.
|
||||
|
||||
You will have to register your bouncer through the `cscli` as well:
|
||||
|
||||
```sh
|
||||
docker exec crowdsec cscli bouncers list
|
||||
docker exec crowdsec cscli bouncers add traefikBouncer
|
||||
```
|
||||
|
||||
This should give you an API key. Place it in the environment variable `CROWDSEC_BOUNCER_API_KEY: <your-key-here>`.
|
||||
Additionally, you should add the `CROWDSEC_AGENT_HOST: crowdsec:8080` environment variable (assuming the crowdsec
|
||||
docker _service_ is called `crowdsec`) - the port is standard and you don't need to portmap or expose anything btw.
|
||||
|
||||
### Crowdsec Core Security Engine Configuration
|
||||
|
||||
In order for the crowdsec security engine to be able to detect intruders, it needs access to the logs of the other
|
||||
containers on the server. To do this, you can just volume mount: `/var/run/docker.sock:/var/run/docker.sock:ro` and
|
||||
then
|
||||
|
||||
Check out [https://app.crowdsec.net/hub/configurations](https://app.crowdsec.net/hub/configurations) if there are logparsers available for the service you want
|
||||
to integrate.
|
||||
|
||||
#### Acquisitions
|
||||
|
||||
In the `acquis.d` directory (volume mapped into the `crowdsec` container to `./acquis.d:/etc/crowdsec/acquis.d`),
|
||||
you should add YAML files for each source you want the crowdsec engine to scan for criminals and other scum:
|
||||
|
||||
```txt
|
||||
acquis.d/
|
||||
├── gitea.yaml
|
||||
└── traefik.yaml
|
||||
```
|
||||
|
||||
File Contents:
|
||||
|
||||
```yaml
|
||||
# traefik.yaml
|
||||
filenames:
|
||||
- /var/log/traefik/*
|
||||
labels:
|
||||
type: traefik
|
||||
```
|
||||
|
||||
```yaml
|
||||
# gitea.yaml
|
||||
source: docker
|
||||
container_name:
|
||||
- gitea
|
||||
labels:
|
||||
type: gitea
|
||||
```
|
||||
|
||||
`traefik.yml` is a `filename` based acquisition file, meaning you need to configure the `traefik` container to
|
||||
output access and system logs into a directory that is volume-mapped so that it's available to the crowdsec
|
||||
container (`traefik-logs:/var/log/traefik/:ro` and associated `traefik-logs:/var/log/traefik/` on traefik).
|
||||
|
||||
The acquisition file for the `gitea` service is using the `docker` source. So it'll read the `docker logs`. The
|
||||
cool thing about this, is that you dont have to do any extra configuration on the gitea side.
|
||||
|
||||
To configure `traefik` to output logs into a file (default it just outputs to stdout/stderr for no-one to read),
|
||||
add the following to your static config (`traefik.yml`) - make sure to `docker compose up -d --force-recreate`
|
||||
every time you edit the config (and want to apply the changes):
|
||||
|
||||
```yaml
|
||||
# ... at the end of traefik.yml
|
||||
log:
|
||||
level: INFO
|
||||
filePath: /var/log/traefik/traefik.log
|
||||
accessLog:
|
||||
filePath: /var/log/traefik/access.log
|
||||
```
|
||||
|
||||
Also, in docker compose file, install some collections:
|
||||
|
||||
```yaml
|
||||
# in crowdsec container spec
|
||||
environment:
|
||||
GID: "$(GID-1000)"
|
||||
COLLECTIONS: "crowdsecurity/linux crowdsecurity/traefik crowdsecurity/whitelist-good-actors LePresidente/gitea"
|
||||
```
|
||||
|
||||
#### Geofenching
|
||||
|
||||
You might have lost the bouncer - check with `docker exec crowdsec cscli bounders list`.
|
||||
|
||||
I am hosting some services that may produce some false-flags by crowdsec, so I will be whitelisting my country. To
|
||||
do this, we need to register a country-code whitelist
|
||||
[postoverflow](https://docs.crowdsec.net/docs/whitelist/create_postoverflow/) in the `postoverflows` directory,
|
||||
which is volume mapped `./postoverflows:/etc/crowdsec/postoverflows/`:
|
||||
|
||||
```yaml
|
||||
# postoverflow/s01-whitelist/sc-countries-whitelist.yaml
|
||||
name: my/whitelist
|
||||
description: Whitelist trusted regions
|
||||
whitelist:
|
||||
reason: Whitelisted country
|
||||
expression:
|
||||
- "evt.Enriched.IsoCode == 'DK'" # NO! Not anymore!
|
||||
```
|
||||
|
||||
Note that the data is not "enriched" with the IsoCode yet. You need to install the `geoip-enrich` thing:
|
||||
|
||||
```sh
|
||||
docker exec crowdsec cscli parsers install crowdsecurity/geoip-enrich
|
||||
```
|
||||
|
||||
This solution is not very sophisticated, so I might change this to something less "sledgehammer"-y in the future.
|
@ -1,316 +0,0 @@
|
||||
+++
|
||||
date = '2025-04-14'
|
||||
draft = true
|
||||
title = "How to Host Docker Containers Easily in The Cloud"
|
||||
tags = ["howto", "tutorial", "web"]
|
||||
categories = ["technical"]
|
||||
+++
|
||||
|
||||
In this post, we will be going over how to set up a [portainer](https://www.portainer.io/) managed docker environment,
|
||||
and how to use it. This is ideal if you want to host a personal website, a [blog](/posts/how-to-blog), a personal
|
||||
[github](git.gtz.dk) or whatever your development heart desire.
|
||||
If you choose to follow along, by the end of it, you will have an environment where you can just add or remove docker
|
||||
based services at a whim using a nice web-based interface.
|
||||
|
||||
I assume that you already know about `docker` and `docker compose` yaml syntax. If you don't, may I recommend the
|
||||
wonderful official [docker tutorial](https://docs.docker.com/get-started/workshop/) - once you're done with that come
|
||||
back here. Or just read on and roll with the punches.
|
||||
|
||||
Oh yea, you should also have good knowledge and experience working on GNU/Linux systems, as you'll be doing a lot of
|
||||
management and interaction with the terminal both during the setup process and during maintenance.
|
||||
|
||||
## Server
|
||||
|
||||
The very first thing to get is a server. This can either be the machine you're currently using if you don't want
|
||||
to mess around on the public internet, or it could be an actual desktop you have set up with a public IP. Or
|
||||
it could be a VPS (Virtual Private Server) - which is just a fancy word for a "cloud computer" that someone
|
||||
else hosts and powers, and you just get an SSH connection to it. Any VPS provider will work, but [digital
|
||||
ocean](https://www.digitalocean.com/) or [linode](https://www.linode.com/) are very affordable and easy to use
|
||||
VPS providers. As long as you get a VPS and avoid a *webhotel*, you should be fine (side note: web hotels are a
|
||||
scam and you shouldn't ever use them - especially not if you're tech-savvy enough to read this blog).
|
||||
|
||||
Once you have your server, [install](https://docs.docker.com/engine/install/) docker on it. Preferably the latest
|
||||
version.
|
||||
|
||||
## Traefik and Portainer
|
||||
|
||||
Traefik is a load balancer / application proxy that makes it easy for you to route network traffic into your various
|
||||
services on your server. By using traefik, you can have multiple docker containers, each providing their own service on
|
||||
a single server, and traefik just routes user traffic based on the URL request, or ports used.
|
||||
|
||||
Portainer is a web-based docker container management GUI (Graphical User Interface) - if you've tried Docker Desktop,
|
||||
think if portainer as a web-based version of that.
|
||||
|
||||
Getting traefik and portainer up and runinng is done by creating a new `docker-compose.yml` file on your server
|
||||
and adding them as individual services. Just to keep things tidy, you should make a directory for all you are
|
||||
going to do here. Do the following on your server.
|
||||
|
||||
```sh
|
||||
# Make the config directory in your $HOME dir - this is where
|
||||
# we'll be working throughout the tutorial. If not specified
|
||||
# otherwise, you should only be editing files inside this directory.
|
||||
mkdir -p ~/config
|
||||
mkdir -p ~/config/traefik-data
|
||||
mkdir -p ~/config/portainer-data
|
||||
cd ~/config
|
||||
|
||||
# Create an empty yaml file
|
||||
touch docker-compose.yml
|
||||
```
|
||||
|
||||
It might be a good idea to initialize the `config` directory as a (local) `git` project. That way you will always have
|
||||
a history of what you have been done, and what you did when you (inevitably) break things. This I will leave up to you
|
||||
though (you should gitignore the `portainer-data` directory, since that's managed by portainer and may contain a bunch
|
||||
of stuff you don't want).
|
||||
|
||||
Inside the new `docker-compose.yml` file, you should put the following content. Simply open the file using your favorite
|
||||
terminal text editor and paste the following. Note! Don't start the stack yet - we still need to configure a bunch of
|
||||
things.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:latest
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- proxy
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./traefik-data/traefik.yml:/traefik.yml:ro
|
||||
- ./traefik-data/acme.json:/acme.json
|
||||
- ./traefik-data/configurations:/configurations
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=proxy
|
||||
- traefik.http.routers.traefik-secure.entrypoints=websecure
|
||||
- traefik.http.routers.traefik-secure.rule=Host(`traefik.example.com`)
|
||||
- traefik.http.routers.traefik-secure.service=traefik
|
||||
- traefik.http.routers.traefik-secure.middlewares=user-auth@file
|
||||
- traefik.http.routers.traefik-secure.service=api@internal
|
||||
environment:
|
||||
- "CF_DNS_API_TOKEN=" # ADD YOUR OWN DNS API TOKEN HERE
|
||||
- "CF_ZONE_API_TOKEN=" # ADD YOUR OWN DNS API TOKEN HERE
|
||||
|
||||
portainer:
|
||||
image: portainer/portainer-ce:alpine
|
||||
container_name: portainer
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- proxy
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- ./portainer-data:/data
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network=proxy
|
||||
- traefik.http.routers.portainer-secure.entrypoints=websecure
|
||||
- traefik.http.routers.portainer-secure.rule=Host(`portainer.example.com`)
|
||||
- traefik.http.routers.portainer-secure.service=portainer
|
||||
- traefik.http.services.portainer.loadbalancer.server.port=9000
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
```
|
||||
|
||||
Whew! That's a lot. Let's break it down. We define two services `traefik` and `portainer`. Starting with the things that
|
||||
are common to both of them, we set the initial niceties, such as the `container_name`, restart policy, security options
|
||||
and set their shared network to be the externally defined `proxy` network. Both services need (read-only) access to the
|
||||
system time for various reasons, so we volume mount `/etc/localtime` to their respective internal `/etc/localtime`. They
|
||||
also both need access to the system docker socket, so we also volume mount that in (again, read-only). Then we map the
|
||||
various configuration directories to their respective services.
|
||||
|
||||
If you haven't used `traefik` before, you might be scratching your head on the `labels` that we set on each of the
|
||||
services. This is just how you configure services to integrate into traefik, enabling you to route your various
|
||||
containers to various subdomains, integrate middle-wares such as forcing HTTPS and setting load-balancer settings etc.
|
||||
|
||||
The `CF_DNS_API_TOKEN` and `CF_ZONE_API_TOKEN` tokens are our cloudflare API keys. If you're using a different DNS
|
||||
provider, you should check the [traefik documentation](https://doc.traefik.io/traefik/https/acme/#providers) to see if
|
||||
your provider is supported, and change the environment variable names accordingly.
|
||||
|
||||
Since the configuration directories are currently empty, the setup won't work yet. Let's add the traefik configuration
|
||||
files first:
|
||||
|
||||
```sh
|
||||
cd ~/config/traefik-data
|
||||
mkdir -p configurations
|
||||
touch traefik.yml
|
||||
touch configurations/dynamic.yml
|
||||
```
|
||||
|
||||
The `traefik.yml` file contains your general traefik configuration. This is where you register certificates, enforce
|
||||
HTTPS and set general settings. The content we're interested in having is the following:
|
||||
|
||||
```yaml
|
||||
api:
|
||||
dashboard: true
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
http:
|
||||
redirections:
|
||||
entryPoint:
|
||||
to: websecure
|
||||
websecure:
|
||||
address: ":443"
|
||||
http:
|
||||
middlewares:
|
||||
- secureHeaders@file
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: your-email-here
|
||||
storage: acme.json
|
||||
keyType: EC384
|
||||
dnsChallenge:
|
||||
provider: cloudflare
|
||||
delayBeforeCheck: 0
|
||||
|
||||
providers:
|
||||
docker:
|
||||
endpoint: "unix:///var/run/docker.sock"
|
||||
exposedByDefault: false
|
||||
file:
|
||||
filename: /configurations/dynamic.yml
|
||||
```
|
||||
|
||||
The first `api` section is pretty self-explanatory enables the web-ui dashboard. You can choose not to do
|
||||
this if you don't want the traefik web dashboard. The `entryPoints` section is a bit more interesting. This
|
||||
is where we enforce that all HTTP web-requests on port `80` will be redirected to port `443` using transport
|
||||
layer security (TLS). You might notice that we specifically mention `letsencrypt` here, this leads us
|
||||
to the `certificatesResolvers` section. Since I am using [cloudflare](https://www.cloudflare.com/)
|
||||
as my DNS (Domain Name Service) provider, I can also use them as my TLS certificate provider as
|
||||
they provide this service. This is a complex topic and if you're interested, I recommend reading
|
||||
[this](https://blog.cloudflare.com/introducing-automatic-ssl-tls-securing-and-simplifying-origin-connectivity/)
|
||||
blog post by cloudflare themselves. Boiling all this jargan down, we are just using cloudflare as a middleman to
|
||||
help us get the little lock icon in the browser when someone visits our website(s). I've set the certificates to
|
||||
automatically update, so I don't have to worry about it ever again.
|
||||
|
||||
The `providers` settings refer to where traefik can route internet traffic to. We simply register `docker` as a service
|
||||
provider as well as the configurations we define in `configurations/dynamic.yml`. Let's take a look at the content of
|
||||
that file.
|
||||
|
||||
```yaml
|
||||
http:
|
||||
middlewares:
|
||||
secureHeaders:
|
||||
headers:
|
||||
sslRedirect: true
|
||||
forceSTSHeader: true
|
||||
stsIncludeSubdomains: true
|
||||
stsPreload: true
|
||||
stsSeconds: 31536000
|
||||
user-auth:
|
||||
basicAuth:
|
||||
users:
|
||||
- "administrator:<password>" # ADD YOUR ADMIN PASSWORD HERE ()
|
||||
|
||||
tls:
|
||||
options:
|
||||
default:
|
||||
cipherSuites:
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
|
||||
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
|
||||
minVersion: VersionTLS12
|
||||
```
|
||||
|
||||
Starting in the `http.middlewares` section, we first register a TLS middleware that we call `secureHeaders` (note that
|
||||
this is the middleware referred in `traefik.yml`) - skipping past the details, this middleware simply adds security
|
||||
headers to each request. Our second middleware, `user-auth` is the authentication method to gain access to the traefik
|
||||
dashboard. Here we set the username `username` and you should generate the password using the `htpasswd` command. This
|
||||
command should be available through the `apache2-utils` package on ubuntu systems, and `extra/apache` on Arch. Simply
|
||||
copy / paste the generated hashed password into your yaml file.
|
||||
|
||||
```sh
|
||||
# -n = output to stdout -B = use bcrypt
|
||||
# Make sure to replace 'administrator' if you want a different username
|
||||
htpasswd -nB administrator
|
||||
```
|
||||
|
||||
## Starting Everything
|
||||
|
||||
We should now have everything set up and ready for starting! Simply navigate to the `~/control` directory and start the
|
||||
docker compose stack.
|
||||
|
||||
```sh
|
||||
# Start the containers (detached)
|
||||
docker compose up -d
|
||||
|
||||
# Follow along with the logs
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
Hopefully there shouldn't be any errors, but if there are, make doubly sure that your TLS settings are set correctly,
|
||||
as that's likely to be the thing to mess up (ask me how I know). If you need additional assistance, the [official
|
||||
traefik docs](https://doc.traefik.io/traefik/) are a great resource. Portainer is fairly fool-proof, so I don't expect
|
||||
that to cause you any problems.
|
||||
|
||||
## TODO
|
||||
- [ ] DNS records, ACME challenges, TXT records, Wildcard A records, CAA records - jesus there's so much shit I've forgotten
|
||||
|
||||
{{< centered image="/6616144.png" >}}
|
||||
|
||||
```yaml
|
||||
services:
|
||||
postgresql:
|
||||
image: postgres:16
|
||||
environment:
|
||||
- POSTGRES_USER=keycloak
|
||||
_ POSTGRES_DB=keycloak
|
||||
- POSTGRES_PASSWORD=secret
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- keycloak
|
||||
|
||||
|
||||
keycloak:
|
||||
image: quay.io/keycloa/keycloak:22
|
||||
restart: always
|
||||
command: start
|
||||
depends_on:
|
||||
- postgresql
|
||||
environment:
|
||||
# traefik handles ssl
|
||||
- KC_PROXY_ADDRESS_FORWARDING=true
|
||||
- KC_HOSTNAME_STRUCT=false
|
||||
- KC_HOSTNAME=keycloak.gtz.dk
|
||||
- KC_PROXY=edge
|
||||
- KC_HTTP_ENABLED=true
|
||||
# connect to the postgres thing
|
||||
- DB=keycloak
|
||||
- DB_URL='jdbc:postgresql://postgres:5432/postgresql?ssl=allow'
|
||||
- DB_USERNAME=keycloak
|
||||
- DB_PASSWORD=secret
|
||||
- KEYCLOAK_ADMIN=admin
|
||||
- KEYCLOAK_ADMIN_PASSWORD=admin
|
||||
networks:
|
||||
- proxy
|
||||
- keycloa
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- port=8080
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
keycloak:
|
||||
```
|
Reference in New Issue
Block a user