valb3r / letsencrypt-helper

Generates and keeps up-to-date your Spring Boot applications' Let's Encrypt or other ACME compliant SSL certificates. Pure Java in a single file of library code. An automated embedded alternative to Certbot and docker-sidecars. No JVM restart is needed on certificate update.
https://valb3r.github.io/letsencrypt-helper
MIT License
35 stars 4 forks source link

Subdomain Support #28

Open HacktheTime opened 1 week ago

HacktheTime commented 1 week ago

I wanted to use reverse proxy to link to different versions of my code (main, beta, alpha) but I have the problem that my certificate is only valid for the main domain. While I am not entirely sure whether certbot makes the domains as one certificate it definitely allows you to request multiple domains.

After trying, due to it being similar to Certbot and it not working I had a fast look. It didn't seem to me like this is currently supported.

I also used a hack to not need to give my code sudo permission nor the annoying all java programs sub 1024 ports. Instead, I went in and used the debug feature that seems to exist to set a port manually and tell my firewall to port forward.

Having support for that officially could be interesting for others.

Also I want to point out that this is my first time working with reverse proxies and I am not very experienced with Spring either.

valb3r commented 1 week ago

@HacktheTime Thanks for your feedback,

Is it the case shown here (case A): letsencrypt-tls-termination

Or the case shown here (case B, embedded): letsencrypt-tls-termination-embedded

You want to implement?

HacktheTime commented 1 week ago

I would encrypt all websites.

Also as reverse proxy I planned to use nginx

All the Websites run on sperate jars.

valb3r commented 6 days ago

Not sure that I understand your use case, is it like this? letsencrypt-same-machine

HacktheTime commented 6 days ago

On first look seems like it. But I don't understand what you mean with the dotted beta line.

Edit: Again however. I am in no way an expert in this and open to changes that ease up the solution while still working on the same base level. (Different version jars, all encrypted etc)

HacktheTime commented 6 days ago

Hm I think I found something which still is incorrect possibly.

NGINX is also on the same Server.

IMA go through everything as far as I can think of.

The main url is just example.com. Beta is beta.example.com Alpha is alpha.example.com.

My Versions are just seperate jar files executed seperately on the same server. Basically a copy of the current version on push.

Alpha is actually running on my localhost during development and I use SSH port forwarding to make it available though my public Server.

Goal is too have all pages encrypted.

Obviously I need to copy the keys to my local PC using sth like scp before start up.

The reason to use a reverse proxy is so you add the version in front if non main and you get put on the right port. Right now I just use setting a port in the address.

I think best would be if the certificate is valid for the main website and sub domains at the same time. Means even if someone manually specifies the port with main website they don't get an invalid encryption error.

valb3r commented 1 day ago

@HacktheTime I think Traefik-proxy is better suited for your problem, it would be hard to solve it within the scope of this project: here is an example docker-compose config:

# Launch sequence
# 1. docker stack init your-stack
# 2. docker network create web --scope swarm -d overlay
# `docker stack deploy --compose-file docker-compose.yml your-stack`

version: "3.3"

services:
  ################################################
  ####        Traefik Proxy Setup           #####
  ###############################################
  traefik:
    image: traefik:v2.0
    restart: always
    container_name: traefik
    ports:
      - "80:80" # <== http
      - "443:443" # <== https
    command:
      #- "--log.level=DEBUG"
      # - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencryptresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.letsencryptresolver.acme.email=your-email.ua@example.com"
      - "--certificatesresolvers.letsencryptresolver.acme.storage=/letsencrypt/acme.json"
    volumes:
      - ./ssl/letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock # <== Volume for docker admin
    networks:
      - web # <== Placing traefik on the network named web, to access containers on this network
    labels:
      #### Labels define the behavior and rules of the traefik proxy for this container ####
      - "traefik.enable=false" # <== Enable traefik on itself to view dashboard and assign subdomain to view it

  ################################################
  ####        Application services          #####
  ###############################################

  some-ui:
    image: project/frontend-image
    depends_on:
      - some-backend
    networks:
      - web
    labels:
      - "traefik.enable=true"
      - "traefik.backend=some-ui"
      - "traefik.http.routers.some-ui.rule=Host(`first-your-domain.com`)"
      - "traefik.http.routers.some-ui.tls.certresolver=letsencryptresolver"

  some-backend:
    restart: always
    image: project/backend-image
    networks:
      - web
    labels:
      - "traefik.enable=true"
      - "traefik.backend=some-backend"
      - "traefik.http.routers.some-backend.rule=Host(`second-your-domain.com`) && PathPrefix(`/api-proxy`)" # Stripping /api-proxy from backend requests
      - "traefik.http.routers.some-backend.middlewares=some-backend-stripprefix"
      - "traefik.http.routers.some-backend.tls.certresolver=letsencryptresolver"
      - "traefik.http.middlewares.some-backend-stripprefix.stripprefix.prefixes=/api-proxy"

  some-other-ui:
    image: project/other-frontend-image
    depends_on:
      - some-backend
    networks:
      - web
    labels:
      - "traefik.enable=true"
      - "traefik.backend=some-other-ui"
      - "traefik.http.routers.some-other-ui.rule=Host(`third-your-domain.com`)"
      - "traefik.http.routers.some-other-ui.tls.certresolver=letsencryptresolver"

networks:
  web:
    external: true
HacktheTime commented 1 day ago

You mentioned a "your-stack" I didn't have one previously so just sth random like "website" will do? (my applications were not running in docker previously)

Changes I need to do are

Email: your-email.ua@example.com

the domains with url1: first-your-domain.com url2: second-your-domain.com url3: third-your-domain.com

right?

however, how exactly does this redirect them to the right ports?

I mean they run on different ports after all on the same server. But https → http alpha +2 → 8062, 8072 beta +1 → 8061, 8071 main +0 → 8060, 8070

because normally from what I saw they try to detect that automatically but in my case every of them does the same things in most parts.

valb3r commented 1 day ago

First of all, this would require to deploy all your apps inside docker containers (within docker-compose infrastructure)

Yes, you need to supply:

  1. email - your-email.ua@example.com, LetsEncrypt will send you mails there Domains: url1: first-your-domain.com url2: second-your-domain.com url3: third-your-domain.com these are the domains of your services, note that for some-backend there is also && PathPrefix(/api-proxy) that removes prefixes

however, how exactly does this redirect them to the right ports?

All those containers live in web network, Traefik will route the requests to containers, because all of them use labels telling how to interpret each of that

valb3r commented 1 day ago

your-stack is simply docker stack name - https://docs.docker.com/reference/cli/docker/stack/