-
Has anyone managed to set this up yet? For very simple Rails apps I think it would be great to have Traefik get a certificate through Let's Encrypt and terminate TLS on the same machine that's running the app. That would also mean no cloud-vendor specific TLS termination and load balancing, which is very much in the spirit of this project... Further reading: https://doc.traefik.io/traefik/v1.7/user-guide/docker-and-lets-encrypt/ |
Beta Was this translation helpful? Give feedback.
Replies: 14 comments 37 replies
-
It's currently not possible without manual work, but I think we should be able to support this very soon. We need to make both |
Beta Was this translation helpful? Give feedback.
-
Just managed to get https to work with Lets encrypt using the following configuration on PR #100: servers:
web:
hosts:
- 206.1*9.***.30
labels:
traefik.http.routers.kiqr_cloud.rule: Host(`example.com`)
traefik.http.routers.kiqr_cloud_secure.entrypoints: websecure
traefik.http.routers.kiqr_cloud_secure.rule: Host(`example.com`)
traefik.http.routers.kiqr_cloud_secure.tls: true
traefik.http.routers.kiqr_cloud_secure.tls.certresolver: letsencrypt
traefik:
options:
publish:
- "443:443"
volume:
- "/letsencrypt/acme.json:/letsencrypt/acme.json"
args:
entryPoints.web.address: ":80"
entryPoints.websecure.address: ":443"
certificatesResolvers.letsencrypt.acme.email: "please@dont.spam"
certificatesResolvers.letsencrypt.acme.storage: "/letsencrypt/acme.json"
certificatesResolvers.letsencrypt.acme.httpchallenge: true
certificatesResolvers.letsencrypt.acme.httpchallenge.entrypoint: web But first you'll have to manually create the acme.json file and give it correct permissions on each hosts: mkdir -p /letsencrypt && touch /letsencrypt/acme.json && chmod 600 /letsencrypt/acme.json |
Beta Was this translation helpful? Give feedback.
-
It probably goes without saying for most of you; but again, up way too late...you also need valid domain names, etc in the You can bounce between:
as needed. You should be able to discern the errors from the Traefik logs. A few extra notes:
servers:
web:
hosts:
- x.x.x.x
labels:
traefik.http.routers.kiqr_cloud.rule: Host(`mrsktest.yourdomain.com`)
traefik.http.routers.kiqr_cloud_secure.entrypoints: websecure
traefik.http.routers.kiqr_cloud_secure.rule: Host(`mrsktest.yourdomain.com `)
traefik.http.routers.kiqr_cloud_secure.tls.certresolver: letsencrypt
.
.
.
traefik:
options:
publish:
- "443:443"
volume:
- "/letsencrypt/acme.json:/letsencrypt/acme.json"
args:
entryPoints.web.address: ":80"
entryPoints.websecure.address: ":443"
certificatesResolvers.letsencrypt.acme.email: "your.email@yourdomain.com"
certificatesResolvers.letsencrypt.acme.storage: "/letsencrypt/acme.json"
certificatesResolvers.letsencrypt.acme.httpchallenge: true
certificatesResolvers.letsencrypt.acme.httpchallenge.entrypoint: web
And again, remember, if you don't know what's wrong, it's probably Traefik. ;)
If all eventually goes well, you should have some json data inside your Addendum: Ultimately, you're looking for something in the traefik logs similar to:
And |
Beta Was this translation helpful? Give feedback.
-
I ended up utilizing a bunch of things from this discussion to get wildcard certificates configured for my setup and figured I'd share back the relevant parts. This was also to get full(strict) SSL connections from Cloudflare to our hosts. To do wildcard certificates with ACME(letsencrypt) you have to do it via a DNS challenge, I'm using Cloudflare but traefik supports a bunch of providers. First thing you'll need is to grab your global API key from Cloudflare, unfortunately you can't create a scoped access token for this, it has to be the global token. Add this to your existing .env secrets file( Run the command on your server to create the acme.json permissions file as mentioned by @kjellberg
Finally add in some additional traefik options, I've also enabled force https redirects via @cschep's comment.
The only thing I found that's a bit weird and maybe it's normal with Traefik is that it complains about an invalid hostname but then later on mentions it already has a certificate for the same hostname. I initially was using HostRegexp to match the host name via labels on the server but I couldn't get that to work at all. If anyone has any pointers I'm all ears.
|
Beta Was this translation helpful? Give feedback.
-
I wanted to redirect any non-www and non-http traffic to https://www, sharing my config here in case it helps anyone else: servers:
web:
hosts:
- southwestruby.com
labels:
traefik.http.routers.southwestruby.rule: Host(`southwestruby.com`)
traefik.http.routers.southwestruby.middlewares: addwww
traefik.http.routers.southwestruby_secure.entrypoints: websecure
traefik.http.routers.southwestruby_secure.rule: Host(`southwestruby.com`)
traefik.http.routers.southwestruby_secure.tls: true
traefik.http.routers.southwestruby_secure.tls.certresolver: letsencrypt
traefik.http.routers.southwestruby_secure.middlewares: addwww
traefik.http.routers.wwwsouthwestruby.rule: Host(`www.southwestruby.com`)
traefik.http.routers.wwwsouthwestruby.middlewares: addwww
traefik.http.routers.wwwsouthwestruby_secure.entrypoints: websecure
traefik.http.routers.wwwsouthwestruby_secure.rule: Host(`www.southwestruby.com`)
traefik.http.routers.wwwsouthwestruby_secure.tls: true
traefik.http.routers.wwwsouthwestruby_secure.tls.certresolver: letsencrypt
traefik.http.middlewares.addwww.redirectregex.regex: ^(?:http|https)://(?:www\.)?(.*)
traefik.http.middlewares.addwww.redirectregex.replacement: "https://www.$1" |
Beta Was this translation helpful? Give feedback.
-
Hey, guys, thank you for sharing your configs! I tried a few of them and didn't have any success; maybe I missed something? When I open http://answers.wheres.me, it shows a What I did:
config/deploy.yml
mrsk traefik logs
|
Beta Was this translation helpful? Give feedback.
-
I am getting these error logs from
Here is my # Name of your application. Used to uniquely configure containers.
service: hp
# Name of the container image.
image: nayvy/hp
# Deploy to these servers.
servers:
web:
hosts:
- 195.x.y.206
labels:
traefik.http.routers.hp.rule: Host(`hp.com`)
traefik.http.routers.hp.entrypoints: websecure
traefik.http.routers.hp.tls.certresolver: letsencrypt
traefik:
options:
publish:
- "443:443"
volume:
- "/letsencrypt/acme.json:/letsencrypt/acme.json"
args:
entryPoints.web.address: ":80"
entryPoints.websecure.address: ":443"
entryPoints.web.http.redirections.entryPoint.to: websecure
entryPoints.web.http.redirections.entryPoint.scheme: https
entryPoints.web.http.redirections.entrypoint.permanent: true
entrypoints.websecure.http.tls: true
entrypoints.websecure.http.tls.domains[0].main: "hp.com"
entrypoints.websecure.http.tls.domains[0].sans: "*.hp.com"
certificatesResolvers.letsencrypt.acme.email: "kaka@hp.com"
certificatesResolvers.letsencrypt.acme.storage: "/letsencrypt/acme.json"
certificatesresolvers.letsencrypt.acme.dnschallenge.provider: cloudflare
env:
secret:
- CLOUDFLARE_API_KEY
clear:
CLOUDFLARE_EMAIL: 'my@gmail.com'
# Credentials for your image host.
registry:
# Specify the registry server, if you're not using Docker Hub
server: ghcr.io
username: nayvy
password:
- KAMAL_REGISTRY_PASSWORD
builder:
args:
RUBY_VERSION: 3.2.2
RAILS_ENV: production
secrets:
- KAMAL_REGISTRY_PASSWORD
cache:
type: registry
# multiarch: false
remote:
arch: amd64
host: ssh://root@195.x.y.206
# Configure a custom healthcheck (default is /up on Rails 7, change when you upgrade)
healthcheck:
path: /
# Inject ENV variables into containers (secrets come from .env).
env:
clear:
RAILS_LOG_TO_STDOUT: 1
RAILS_SERVE_STATIC_FILES: 1
secret:
- RAILS_MASTER_KEY
- POSTGRES_USER
- POSTGRES_PASSWORD
- POSTGRES_DB
- POSTGRES_HOST
- DATABASE_URL
- PRODUCTION_REDIS_URL
My database is running on a remote server and I'm connecting to it using the I cannot access the app from my custom domain nor the IP |
Beta Was this translation helpful? Give feedback.
-
Hi 👋 I opened a PR to put your solution in the docs: basecamp/kamal-site#41 Feel free to provide feedback! thanks |
Beta Was this translation helpful? Give feedback.
-
Anyone know how to REMOVE letsencrypt after having added it? I removed it from my kamal
|
Beta Was this translation helpful? Give feedback.
-
At some point, it might be helpful to work with a traefik.yaml file for configuration. Unfortunately the files configuration option is not yet implemented for the traefik role, so we have to copy the traefik.yaml file to the host to mount it via a volume.
for the future it would be helpful to be able to use this
This works for accessory roles and maybe this functionality can move some level up to be accessible for traefik as well. |
Beta Was this translation helpful? Give feedback.
-
I'm attaching an extensively documented configuration that meets the following
A bunch of Traefik + Docker guides exist out there. A few of them have wildcard I've tried to use Traefik's examples and documentation first without input from I use Terraform and Ansible for deployment and configuration. I'm using a very Notes
config/deploy.yml################################################################################
#
# Configuration Notes
#
################################################################################
#
# 1) Regarding A+ ratings in SSL Labs reports [1]:
# Many guides provide options that add security headers [2]. The examples
# that I found were not documented very well, and it might be worth just
# following the "HTTP Headers - OWASP Cheat Sheet Series" [3]; however, AFAIK
# Rails already provides sane defaults [4] for you.
#
# [1] - https://www.ssllabs.com/ssltest/
# [2] - https://doc.traefik.io/traefik/middlewares/http/headers/
# [3] - https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html
# [4] - https://guides.rubyonrails.org/security.html#http-security-headers
#
# 2) SSL Labs provides a list of local tools [1] that can be used for SSL
# assessment on your servers. The "testssl.sh" [2] tool works well and can be
# run straight from Docker.
#
# Example:
#
# $ docker run --rm -ti drwetter/testssl.sh https://test1.deploy-test.example.com
#
# [1] - https://github.com/ssllabs/research/wiki/Assessment-Tools
# [2] - https://github.com/drwetter/testssl.sh
#
#
# 3) Lots of guides have assume_ssl turned ON and force_ssl turned OFF; however,
# the "config/environments/production.rb" "config.assume_ssl"comments have
# this to say:
#
# Can be used together with config.force_ssl for Strict-Transport-Security
# and secure cookies.
#
# More discussion from the maybe-finance project [1]:
#
# ezekg commented:
#
# It's worth mentioning that any well-behaved reverse proxy should be
# setting the X-Forwarded-* headers. Namely, X-Forwarded-Proto, which Rails
# uses to determine if the request is coming from a TLS-terminating reverse
# proxy. If X-Forwarded-Proto: https, then Rails will NOT redirect the
# request, because it knows it's coming from a TLS-terminating reverse
# proxy. So the only case where config.force_ssl = false is actually needed
# is for misbehaving reverse proxies.
#
# Later a note [2] is added saying that Campfire turns ON both of these
# options in production.
#
# The Rails Action Dispatch SSL docs say more about the benefits of
# "config.force_ssl" [3].
#
# Turning both on seems to work fine with Kamal/Traefik though, where SSL is
# terminated at the load balancer and traffic from the load balancer to app
# servers is insecure. I need to study the headers in more detail. I did not
# dig into the source for this issue, yet.
#
# [1] - https://github.com/maybe-finance/maybe/issues/308#issuecomment-1944936184
# [2] - https://github.com/maybe-finance/maybe/issues/308#issuecomment-1934615353
# [3] - https://api.rubyonrails.org/v7.1.3.2/classes/ActionDispatch/SSL.html
#
# ############################################################################
# # Example environment config
# ############################################################################
# # config/environments/production.rb
#
# # 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
#
# # 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.force_ssl = true
#
################################################################################
################################################################################
#
# Extra Debugging Tips
#
################################################################################
#
# 1) Examine the command line arguments passed to docker container on the
# running container on the app server:
#
# $ docker inspect -f "{{json .Config.Cmd}}" traefik | jq
#
# [
# "--providers.docker",
# "--log.level=DEBUG",
# "--entrypoints.web.address=:80",
# "--entrypoints.websecure.address=:443",
# "--providers.file.filename=/letsencrypt/tls.yml",
# "--certificatesresolvers.letsencrypt.acme.email=johndoe@example.com",
# "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json",
# "--certificatesresolvers.letsencrypt.acme.dnschallenge",
# "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=linode",
# "--entryPoints.web.http.redirections.entryPoint.to=websecure",
# "--entryPoints.web.http.redirections.entryPoint.scheme=https",
# "--entryPoints.web.http.redirections.entrypoint.permanent"
# ]
#
# 2) Examine the labels on the running traefik docker container on the app
# server
#
# docker inspect -f "{{json .Config.Labels}}" traefik | jq
# {
# "org.opencontainers.image.description": "A modern reverse-proxy",
# "org.opencontainers.image.documentation": "https://docs.traefik.io",
# "org.opencontainers.image.source": "https://github.com/traefik/traefik",
# "org.opencontainers.image.title": "Traefik",
# "org.opencontainers.image.url": "https://traefik.io",
# "org.opencontainers.image.vendor": "Traefik Labs",
# "org.opencontainers.image.version": "v2.9.10",
# "traefik.http.routers.catchall.entryPoints": "web",
# "traefik.http.routers.catchall.priority": "1",
# "traefik.http.routers.catchall.rule": "PathPrefix(`/`)",
# "traefik.http.routers.catchall.service": "unavailable",
# "traefik.http.services.unavailable.loadbalancer.server.port": "0"
# }
#
################################################################################
################################################################################
# Common variables
#
# kamal uses ERB Ruby module to read config:
# https://github.com/basecamp/kamal/blob/9ec3895dab2772915c44f3a348e54de58981857d/lib/mrsk/configuration.rb#L29
################################################################################
<%
service_name = "hetzner_deploy_test"
registry_username = "johndoe"
ip = "192.168.1.10"
domain = "deploy-test.example.com"
letsencrypt_email = "johndoe@example.com"
letsencrypt_provider = "linode"
letsencrypt_provider_secret_name = "LINODE_TOKEN"
%>
# Name of your application. Used to uniquely configure containers.
service: <%= service_name %>
# Name of the container image.
image: <%= registry_username %>/<%= service_name %>
# Deploy to these servers.
servers:
web:
hosts:
- <%= ip %>
labels:
##########################################################################
# Host Rule:
# Check if the request domain (host header value) targets one of the
# given domains.
# Example: Host(`example.com`, ...)
#
# HostRegexp Rule:
# Match the request domain. See "Regexp Syntax" below.
# Example: HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...)
#
# NOTES:
# "Host" rules are for HTTP routers [1] and "HostSNI" rules are for TCP
# routers [2].
#
# If both HTTP routers and TCP routers listen to the same entry points,
# the TCP routers will apply before the HTTP routers. If no matching route
# is found for the TCP routers, then the HTTP routers will take over.
#
# [1] - https://doc.traefik.io/traefik/routing/routers/#rule
# [2] - https://doc.traefik.io/traefik/routing/routers/#rule_1
#
##########################################################################
# FAQ:
##########################################################################
#
# 1) Why the "subdomain" part?
#
# Regexp Syntax [1]
#
# HostRegexp, PathPrefix, and Path accept an expression with zero or
# more groups enclosed by curly braces, which are called named regexps.
# Named regexps, of the form {name:regexp}, are the only expressions
# considered for regexp matching. The regexp name (name in the above
# example) is an arbitrary value, that exists only for historical
# reasons.
#
# Any regexp supported by Go's [2] regexp package may be used. For
# example, here is a case insensitive path matcher syntax:
#
# Path(`/{path:(?i:Products)}`).
#
# [1] - https://doc.traefik.io/traefik/routing/routers/# rule
# [2] - https://golang.org/pkg/regexp/
#
# 2) Why not combine everything into the single Regexp?
#
# You can choose get fancy with the HostRegexp but I prefer using the
# OR (||) syntax here and keeping it a bit simpler to read. We have:
#
# a) HostRegexp for wildcard
# b) Host for base domain
# c) Not listed, but anything else you want to match including other
# completely different domains
#
# 3) I see some examples that look like this: HostRegexp(`.+`)
# Can I use that more simple regex?
#
# No, this is Traefik v3 syntax which is not stable yet (currently in
# RC). Kamal uses v2 which is the current stable release which doesn't
# support that syntax [1].
#
# [1] - https://doc.traefik.io/traefik/v3.0/migration/v2-to-v3/#new-v3-syntax-notable-changes
#
traefik.http.routers.<%= service_name %>.rule: HostRegexp(`{subdomain:[a-zA-Z0-9-]+}.<%= domain %>`) || Host(`<%= domain %>`)
# Allow request only from the predefined entry point named "websecure";
# that is, it won't listen to the insecure "web" entrypoint that doesn't
# have SSL enabled.
#
# https://doc.traefik.io/traefik/routing/routers/#entrypoints
traefik.http.routers.<%= service_name %>.entrypoints: websecure
##########################################################################
# When a TLS section is specified, it instructs Traefik that the current
# router is dedicated to TLS requests only (and that the router should
# ignore non-TLS requests).
#
# By default, a router with a TLS section will terminate the TLS
# connections, meaning that it will send decrypted data to the services.
#
# https://doc.traefik.io/traefik/routing/routers/#tls
#
##########################################################################
# NOTE: this option is implied if other ".tls" options are used and does
# not have to be explicitly set.
#traefik.http.routers.<%= service_name %>.tls: true
# If certResolver is defined, Traefik will try to generate certificates
# based on routers Host & HostSNI rules.
#
# NOTE: this much match the name from the traefik config
# certificatesresolvers args, e.g.:
#
# certificatesresolvers.letsencrypt.acme.dnschallenge: true
# ^^^^^^^^^^^
traefik.http.routers.<%= service_name %>.tls.certresolver: letsencrypt
# You can set SANs (alternative domains) for each main domain [1]. Every
# domain must have A/AAAA records pointing to Traefik. Each domain & SAN
# will lead to a certificate request.
#
# References:
# [1] - https://doc.traefik.io/traefik/routing/routers/#domains
#
traefik.http.routers.<%= service_name %>.tls.domains[0].main: <%= domain %>
traefik.http.routers.<%= service_name %>.tls.domains[0].sans: "*.<%= domain %>"
traefik:
options:
publish:
- "443:443"
volume:
- "/letsencrypt/acme.json:/letsencrypt/acme.json"
- "/letsencrypt/tls.yml:/letsencrypt/tls.yml"
labels:
# Kamal provides a "catchall" configuration [1] in its default labels for
# the traefik container which ensures a 502 status code is served rather
# than a 404 if no containers are available. You can see more details in the
# traefik docs [2].
#
# Most of the traefik docs name the port 80 entrypoint "web" and port 443
# entrypoint "websecure" which is what I've used throughout this example;
# however, Kamal has named it "http". I prefer "web" because "http" is
# already used for other things like Entrypoints HTTP Options which can be
# a little confusing. For example:
#
# entryPoints.web.http...
# vs.
# entryPoints.http.http...
#
# Here, the Kamal default "http" is overriden with "web"
#
# The labels can be inspected on the running container on the app server
# with this command (must install jq utility):
#
# $ docker inspect -f "{{json .Config.Labels}}" traefik | jq
#
# [1] - https://github.com/basecamp/kamal/blob/e8b9f8907f16416accb47ba2208185f1ea91754b/lib/kamal/commands/traefik.rb#L11
# [2] - https://doc.traefik.io/traefik/getting-started/faq/#xxx-instead-of-404
#
traefik.http.routers.catchall.entryPoints: web
args:
############################################################################
# Entrypoints
#
# EntryPoints are the network entry points into Traefik. They define the
# port which will receive the packets, and whether to listen for TCP or
# UDP.
#
# https://doc.traefik.io/traefik/routing/entrypoints/#entrypoint
############################################################################
# Define ports for http and https traffic here:
entrypoints.web.address: ":80"
entrypoints.websecure.address: ":443"
############################################################################
# TLS Options (optional)
#
# Some options like these TLS options are not able to be set with docker
# labels [1], yet. Here we provide the filename for these options. This
# must be added in the volume section above and the file needs to be
# created before kamal setup on the server itself just like with the
# acme.json file.
#
# NOTE: This is completely optional and only needed if you want to
# add extra TLS options like "sniStrict: true" [2].
#
# https://doc.traefik.io/traefik/https/tls/#tls-options
#
# References:
# [1] - https://github.com/basecamp/kamal/discussions/674
# [2] - https://doc.traefik.io/traefik/https/tls/#strict-sni-checking
############################################################################
# The file provider lets you define the dynamic configuration in a YAML
# or TOML file.
# https://doc.traefik.io/traefik/providers/file/#filename
providers.file.filename: "/letsencrypt/tls.yml"
############################################################################
# Let's Encrypt: common configuration
#
# https://doc.traefik.io/traefik/https/acme/
############################################################################
# Email address used for registration. (Required)
certificatesresolvers.letsencrypt.acme.email: "<%= letsencrypt_email %>"
# File or key used for certificates storage. (Required)
certificatesresolvers.letsencrypt.acme.storage: "/letsencrypt/acme.json"
############################################################################
# Let's Encrypt: httpChallenge (Optional)
#
# https://doc.traefik.io/traefik/https/acme/#httpchallenge
############################################################################
# Use a HTTP-01 ACME challenge. (Optional)
#certificatesresolvers.letsencrypt.acme.httpchallenge: true
# EntryPoint to use for the HTTP-01 challenges. (Required)
#certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint: web
############################################################################
# Let's Encrypt: dnsChallenge
#
# https://doc.traefik.io/traefik/https/acme/#dnschallenge
############################################################################
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge. Note: mandatory
# for wildcard certificate generation. (Optional)
certificatesresolvers.letsencrypt.acme.dnschallenge: true
# DNS provider used. (Required)
certificatesresolvers.letsencrypt.acme.dnschallenge.provider: <%= letsencrypt_provider %>
############################################################################
# Globally redirect http to https
#
# https://doc.traefik.io/traefik/routing/entrypoints/#redirection
############################################################################
entryPoints.web.http.redirections.entryPoint.to: websecure
entryPoints.web.http.redirections.entryPoint.scheme: https
entryPoints.web.http.redirections.entrypoint.permanent: true
env:
secret:
- <%= letsencrypt_provider_secret_name %>
# Credentials for your image host.
registry:
# Specify the registry server, if you're not using Docker Hub
# server: registry.digitalocean.com / ghcr.io / ...
username: <%= registry_username %>
# Always use an access token rather than real password when possible.
password:
- KAMAL_REGISTRY_PASSWORD
# Inject ENV variables into containers (secrets come from .env).
# Remember to run `kamal env push` after making changes!
env:
clear:
POSTGRES_HOST: "<%= ip %>" # With the pattern: <service_name>-<accessory_name>
REDIS_URL: "redis://<%= ip %>:6379/0" # We need to override the REDIS_URL (used by Sidekiq and your cache_store), same pattern: <service_name>-<accessory_name>
secret:
- KAMAL_REGISTRY_PASSWORD
- RAILS_MASTER_KEY
# Use a different ssh user than root
# ssh:
# user: app
# Configure builder setup.
# builder:
# args:
# RUBY_VERSION: 3.2.0
# secrets:
# - GITHUB_TOKEN
# remote:
# arch: amd64
# host: ssh://app@192.168.0.1
builder:
multiarch: false
local:
arch: amd64
# Use accessory services (secrets come from .env).
# accessories:
# db:
# image: mysql:8.0
# host: 192.168.0.2
# port: 3306
# env:
# clear:
# MYSQL_ROOT_HOST: '%'
# secret:
# - MYSQL_ROOT_PASSWORD
# files:
# - config/mysql/production.cnf:/etc/mysql/my.cnf
# - db/production.sql:/docker-entrypoint-initdb.d/setup.sql
# directories:
# - data:/var/lib/mysql
# redis:
# image: redis:7.0
# host: 192.168.0.2
# port: 6379
# directories:
# - data:/data
accessories:
postgres:
image: postgres:16.2-bullseye
host: <%= ip %>
port: 5432
env:
clear:
POSTGRES_USER: 'postgres'
POSTGRES_DB: "<%= service_name %>_production"
secret:
- POSTGRES_PASSWORD
volumes:
- postgres:/var/lib/postgresql/data
redis:
image: redis:7.2.4-alpine
roles:
- web
port: "6379:6379"
volumes:
- redis:/var/lib/redis
# Configure custom arguments for Traefik
# traefik:
# args:
# accesslog: true
# accesslog.format: json
# Configure a custom healthcheck (default is /up on port 3000)
# healthcheck:
# path: /healthz
# port: 4000
# Bridge fingerprinted assets, like JS and CSS, between versions to avoid
# hitting 404 on in-flight requests. Combines all files from new and old
# version inside the asset_path.
# asset_path: /rails/public/assets
# Configure rolling deploys by setting a wait time between batches of restarts.
# boot:
# limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
# wait: 2
# Configure the role used to determine the primary_host. This host takes
# deploy locks, runs health checks during the deploy, and follow logs, etc.
#
# Caution: there's no support for role renaming yet, so be careful to cleanup
# the previous role on the deployed hosts.
# primary_role: web
# Controls if we abort when see a role with no hosts. Disabling this may be
# useful for more complex deploy configurations.
#
# allow_empty_roles: false /letsencrypt/tls.ymltls:
options:
default:
##########################################################################
# From moz://a SSL Configuration Generator
#
# Intermediate - General-purpose servers with a variety of clients,
# recommended for almost all systems
#
# generated 2024-03-11, Mozilla Guideline v5.7, Traefik 2.9, intermediate
# configuration
#
# Supports Firefox 27, Android 4.4.2, Chrome 31, Edge, IE 11 on Windows 7,
# Java 8u31, OpenSSL 1.0.1, Opera 20, and Safari 9
#
# https://ssl-config.mozilla.org/#server=traefik&version=2.9&config=intermediate&guideline=5.7
# https://doc.traefik.io/traefik/https/tls/#cipher-suites
#
##########################################################################
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
##########################################################################
# With strict SNI checking enabled, Traefik won't allow connections from
# clients that do not specify a server_name extension or don't match any
# of the configured certificates. The default certificate is irrelevant on
# that matter.
#
# NOTE: This will obviously disable all access to your site using anything
# other than the DNS records with SSL certs that you have specifically set
# in the Kamal traefik config. You will not be able to access your site
# using an IP address or DNS record with no cert for instance. This
# setting is completely optional and just an extra security precaution.
#
# https://doc.traefik.io/traefik/https/tls/#strict-sni-checking
#
##########################################################################
sniStrict: true
##########################################################################
# This option allows to set the preferred elliptic curves in a specific
# order.
#
# NOTE: If you leave this section out, you can still get an A+ SSL Labs
# rating; however, the "Key Exchange" will have a grade of 90. The
# testssl.sh utility will give a 100 grade, though. Adding this section
# raises the grade to 100 on the website test. I can't see any differences
# on the web reports. The only significant difference in the # testssl.sh
# reports that I can find are compatibility with Android 7.0; that is,
# setting these more strict curve options limits compatibility with
# Android 7.0 (released on August 22, 2016).
#
# CSV diff (left with curvePreferences enabled, right with defaults):
# < "clientsimulation-android_70","test1.example.com/192.168.1.10","443","INFO","No connection","",""
# ---
# > "clientsimulation-android_70","test1.example.com/192.168.1.10","443","INFO","TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256","",""
#
# NOTE: These options are recommended in the Traefik docs, but I haven't
# found the full justification for these being the "safe" [1] values or if
# they really need to be manually configured or not. AFAIK, Chrome doesn't
# support CurveP521 (secp521r1). Your browser can be tested at SSL
# Labs [2]. It's up to you if you want to chase a 100 grade on the "Key
# Exchange" when you get an A+ rating either way. Just see what's best for
# your environment.
#
# NOTE: The "testssl.sh" [3] tool reports the following defaults when not
# explicitly setting it here:
# Elliptic curves offered: prime256v1 secp384r1 secp521r1 X25519
#
# [1] - https://community.letsencrypt.org/t/when-choosing-an-elliptic-curve-look-for-a-safe-curve/161837/3
# [2] - https://clienttest.ssllabs.com:8443/ssltest/viewMyClient.html
# [3] - https://github.com/drwetter/testssl.sh
#
# https://doc.traefik.io/traefik/https/tls/#curve-preferences
#
##########################################################################
curvePreferences:
# - X25519
- CurveP521
- CurveP384
# - CurveP256 |
Beta Was this translation helpful? Give feedback.
-
@clintbullock Thank you big time on the hints for file dynamic configuration. This will allow me to enable SNI and pass our vuln scanners. Thanks for saving my face!!! |
Beta Was this translation helpful? Give feedback.
-
Hello, I tried setting up the wildcard cert for my domain using letsencrypt and cloudflare and I get this error. It seems to be using the container name instead of my domain name
This is how my # Deploy to these servers.
servers:
web:
hosts:
- 172.178.xx.xx
labels:
traefik.http.routers.httpmock.rule: HostRegexp(`{subdomain:[a-zA-Z0-9-]+}.domain.dev`) || Host(`domain.dev`)
traefik.http.routers.httpmock_secure.entrypoints: websecure
traefik.http.routers.httpmock_secure.tls.certresolver: letsencrypt
traefik.http.routers.httpmock.tls.domains[0].main: "domain.dev"
traefik.http.routers.httpmock.tls.domains[0].sans: "*.domain.dev"
# Configure custom arguments for Traefik
traefik:
options:
publish:
- "443:443"
volume:
- "/letsencrypt/acme.json:/letsencrypt/acme.json"
labels:
traefik.http.routers.catchall.entryPoints: web
args:
accesslog: true
global.sendAnonymousUsage: true
entryPoints.web.address: ":80"
entryPoints.websecure.address: ":443"
entryPoints.web.http.redirections.entryPoint.to: websecure
entryPoints.web.http.redirections.entryPoint.scheme: https
entryPoints.web.http.redirections.entrypoint.permanent: true
certificatesResolvers.letsencrypt.acme.email: "arnold@domain.dev"
certificatesResolvers.letsencrypt.acme.storage: "/letsencrypt/acme.json"
certificatesResolvers.letsencrypt.acme.dnschallenge: true
certificatesResolvers.letsencrypt.acme.dnschallenge.provider: cloudflare
env:
secret:
- CLOUDFLARE_API_KEY
- CLOUDFLARE_EMAIL |
Beta Was this translation helpful? Give feedback.
-
Just wanted to comment here that I have the most difficult time getting my wildcard certs working. Eventually, however, I did get it. But I don't understand why it was broken, and would love if someone more knowledgeable than me could educate me. This was the final working config:
For some reason, I had the add the second The error I kept getting was this:
I hope that error will strengthen the already considerable SEO of looking for:
This |
Beta Was this translation helpful? Give feedback.
Just managed to get https to work with Lets encrypt using the following configuration on PR #100: