Skip to content

Commit 0c6638c

Browse files
committed
acme staging config flag
1 parent 175176c commit 0c6638c

5 files changed

Lines changed: 28 additions & 5 deletions

File tree

example-config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ log_level = "info"
1717
rate_limit_per_second = 0
1818
rate_limit_burst = 0
1919
url = "http://localhost:8080"
20+
acme_staging = false

src/acme.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,18 @@ async fn check_domain_resolves(domain: &str) -> anyhow::Result<()> {
123123
pub async fn run_acme_http01(
124124
domain: String,
125125
existing_credentials_json: String,
126+
use_staging: bool,
126127
port80_permit: Option<Port80Permit>,
127128
progress_tx: mpsc::UnboundedSender<AcmeStep>,
128129
) -> anyhow::Result<AcmeCertResult> {
129130
info!("Starting ACME HTTP-01 certificate issuance for domain: {domain}");
130-
info!("Using Let's Encrypt production environment");
131+
let dir_url = if use_staging {
132+
info!("Using Let's Encrypt staging environment");
133+
LetsEncrypt::Staging.url().to_owned()
134+
} else {
135+
info!("Using Let's Encrypt production environment");
136+
LetsEncrypt::Production.url().to_owned()
137+
};
131138

132139
// DNS pre-flight: verify the domain resolves before attempting ACME.
133140
let _ = progress_tx.send(AcmeStep::CheckingDomain);
@@ -140,7 +147,6 @@ pub async fn run_acme_http01(
140147
let (account, credentials) = if existing_credentials_json.is_empty() {
141148
info!("No stored ACME account found; creating a new one with Let's Encrypt");
142149
let builder = Account::builder().context("Failed to create ACME account builder")?;
143-
let dir_url = LetsEncrypt::Production.url().to_owned();
144150
info!("Registering account at ACME directory: {dir_url}");
145151
let (account, credentials) = builder
146152
.create(
@@ -149,7 +155,7 @@ pub async fn run_acme_http01(
149155
contact: &[],
150156
only_return_existing: false,
151157
},
152-
dir_url,
158+
dir_url.clone(),
153159
None,
154160
)
155161
.await

src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ pub struct EnvConfig {
8484
/// server is restarted on this port using those certificates.
8585
#[arg(long, env = "DEFGUARD_PROXY_HTTPS_PORT", default_value_t = 443)]
8686
pub https_port: u16,
87+
88+
/// Use Let's Encrypt staging environment for ACME issuance.
89+
#[arg(long, env = "DEFGUARD_PROXY_ACME_STAGING", default_value_t = false)]
90+
pub acme_staging: bool,
8791
}
8892

8993
#[derive(thiserror::Error, Debug)]

src/grpc.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub(crate) struct ProxyServer {
6262
/// Shared log receiver - written by `GrpcLogLayer` for every tracing event.
6363
/// Drained during ACME execution to collect proxy log lines for error reporting.
6464
logs_rx: LogsReceiver,
65+
acme_staging: bool,
6566
}
6667

6768
impl ProxyServer {
@@ -74,6 +75,7 @@ impl ProxyServer {
7475
https_cert_tx: broadcast::Sender<(String, String)>,
7576
port80_pause_tx: Option<mpsc::Sender<(oneshot::Sender<()>, oneshot::Receiver<()>)>>,
7677
logs_rx: LogsReceiver,
78+
acme_staging: bool,
7779
) -> Self {
7880
Self {
7981
cookie_key,
@@ -88,6 +90,7 @@ impl ProxyServer {
8890
https_cert_tx,
8991
port80_pause_tx,
9092
logs_rx,
93+
acme_staging,
9194
}
9295
}
9396

@@ -212,6 +215,7 @@ impl Clone for ProxyServer {
212215
https_cert_tx: self.https_cert_tx.clone(),
213216
port80_pause_tx: self.port80_pause_tx.clone(),
214217
logs_rx: Arc::clone(&self.logs_rx),
218+
acme_staging: self.acme_staging,
215219
}
216220
}
217221
}
@@ -389,6 +393,7 @@ impl proxy_server::Proxy for ProxyServer {
389393

390394
let pause_tx = self.port80_pause_tx.clone();
391395
let logs_rx = Arc::clone(&self.logs_rx);
396+
let acme_staging = self.acme_staging;
392397
tokio::spawn(async move {
393398
// Request a graceful hand-off of port 80 from the main HTTP server if it is bound
394399
// there, so the ACME challenge listener can bind.
@@ -432,8 +437,14 @@ impl proxy_server::Proxy for ProxyServer {
432437
}
433438
});
434439

435-
match acme::run_acme_http01(domain.clone(), existing_credentials, permit, progress_tx)
436-
.await
440+
match acme::run_acme_http01(
441+
domain.clone(),
442+
existing_credentials,
443+
acme_staging,
444+
permit,
445+
progress_tx,
446+
)
447+
.await
437448
{
438449
Ok(acme_result) => {
439450
let cert_event = AcmeIssueEvent {

src/http.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ pub async fn run_server(
339339
https_cert_tx,
340340
port80_pause_tx,
341341
Arc::clone(&logs_rx),
342+
env_config.acme_staging,
342343
);
343344

344345
// Preload existing TLS configuration so /api/v1/info can report "disconnected"

0 commit comments

Comments
 (0)