Hi,
I want to share with you a solution I adopted, in order to expose services both to the Internet and to LAN, terminating https connections with the same let’sencrypt certificate via two reverse proxies.
It’s not perfect but I found it fun to implement.
from the Internet
│
│
▼
svc.example.com(public IP) NETHSERVER
────┬───────────────┬─────┬────────────┬────────────
│reverse-proxy │ │ LE certbot │
└───────┬───────┘ └───────┬────┘
│ │
│ │
│ pushes certs to the backend
│ on every renewal
│ │ (via scp)
│ ┌─────────────────┘
│ │
│ │
▼ ▼ ┌────────────┐
┌───────────┐ │Traefik │
│ service │ ◄─┤rev.proxy │
────┴───────────┴───┴────────────┴────────────────
LINUX-SERVER svc.example.com (private IP)
▲
│
│
from the LAN
The concept is based on split horizon DNS in which there are two different addresses to resolve “svc.example.com”:one public and one private. The two long horizontal lines represent the two “front” one public front of the nethserver and one private front of the linux-server that hosts the service.
Clients from the internet resolve svc.example.com via public DNS to a IP address on the RED interface of my nethserver. Clients from the LAN resolve the same svc.example.com via internal DNS server to the private IP of the linux-server.
On Linux-server I run two containers: one contains the service itself that listens to port TCP8001 for example, and the other one contains an instance of traefik reverse proxy that forwards https requests to port TCP8001.
The public reverse proxy is one httpd instance that runs on nethserver and corresponds to the “webserver application” and terminates https connections that forwards to port tcp8001 of the linux-server.
Details:
In order to configure all this mess you have to follow these steps:
- Register on your public DNS zone a new A record that pointa at you public IP on the nethserver.
- Register on your private DNS zone a new A record that points at the private IP of a linux-server in your intranet.
- Gain a let’sencrypt certificate configurin nethserver this way:
under system->certificates->let’s encrypt certificates → +add a domain (add the A record you have registered in step 1&2) - Create a user on the linux server, with the only purpose to send it the updated LE certificate (cert + priv key) at every renewal. (on linux server useradd -md /home/certbot certbot; mkdir /home/certbot/certs )
- On the nethserver console: ssh-copyid certbot@ in order to issue, lather on, automatic scp commands without asking for any password.
- On the nethserver: create a script under
/etc/letsencrypt/renewal-hooks/deploy/15scpcerts
with the following commands:
#!/bin/bash
/usr/bin/scp /etc/letsencrypt/live/<your-nethserver-hostname>/{fullchain.pem,privkey.pem} certbot@<linux-server>:/home/certbot/certs
This way, every time…ok you got it.
7) on the linux-server place this traefik docker-compose.yaml:
version: "3"
networks:
traefik:
external: true
services:
traefik:
image: "traefik:v2.10"
container_name: "traefik"
command:
#- "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.network=traefik"
- "--providers.docker.exposedbydefault=false"
- "--providers.file.directory=/etc/traefik/"
- "--providers.file.watch"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.address=:80"
- "--entryPoints.websecure.forwardedHeaders.insecure=true"
networks:
- "traefik"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./traefik-dynamic-config/:/etc/traefik/"
- "/home/certbot/certs:/certs"
labels:
traefik.http.routers.http-catchall.rule: hostregexp(`{host:.+}`)
traefik.http.routers.http-catchall.entrypoints: web
traefik.http.routers.http-catchall.middlewares: redirect-to-https@docker
traefik.http.middlewares.redirect-to-https.redirectscheme.scheme: https
restart: always
and this for the dynamic configuratin part about certificates:
traefik-dynamic-config/certs-traefik.yml
:
---
tls:
certificates:
- certFile: /certs/fullchain.pem
keyFile: /certs/privkey.pem
this way traefik will use cert and key placed into /home/certbot/certs
- deploy a service, one example in the yaml file:
version: "3"
networks:
traefik:
external: True
services:
test:
image: nginx:latest
container_name: test
ports:
- 8001:80
volumes:
- "./html:/usr/share/nginx/html"
restart: always
networks:
- "traefik"
labels:
- "traefik.enable=true"
- "traefik.http.routers.webservertest.rule=Host(`svc.example.com`)"
- "traefik.http.routers.webservertest.entrypoints=websecure"
- "traefik.http.routers.webservertest.tls=true"
- then you have to configure reverse proxy on the nethserver “webserver application”
under: webserver->create a reverse proxy → name: “https://srv.example.com” destination URL: “http://linux-server:8001”
and that’s all.
Another simpler way shoud be to bypass traefik and private name resolution. You then have to resolve the service with the public ip and configure air-pin-nat on the nethserver, in order to reach the svc.exmple.com from the LAN… but I think the first solution is more elegant and efficient.
thank you for your attention, any comment are appreciated.
bye.
Fabio