authorSergey Poznyakoff <>2018-05-07 08:27:28 (GMT)
committer Sergey Poznyakoff <>2018-05-07 08:27:28 (GMT)
commit95c82ca2a5562e60463a38519157ae1a8b60ac1a (patch) (side-by-side diff)
parentd76f2f28aaff86ffd7e4a049d5ce7cd91885805f (diff)
Improve "file" source
* lib/App/Acmeman/Source/ (new): New options --ignore and --host. * acmeman: Document the "file" source.
Diffstat (more/less context) (ignore whitespace changes)
2 files changed, 77 insertions, 21 deletions
diff --git a/acmeman b/acmeman
index 7edd5e0..143ef43 100755
--- a/acmeman
+++ b/acmeman
@@ -84,7 +84,7 @@ scans B<apache> configuration files for a list of domains.
B<Acmeman> is normally run periodically as a cronjob.
If you plan to serve SSL protected domains using apache, you can skip
-right to the B<APACHE> section.
+right to the B<apache> section.
The following is a short introduction to the B<acmeman> configuration. For
a detailed discussion, see the B<CONFIGURATION> section below.
@@ -127,7 +127,9 @@ the B<domain> section lacks the B<files> keyword.
The special section B<[core]> contains basic settings that control the
program behavior. One of the important settings is B<source>, which declares
an external source from which domain settings must be obtained. As
-of B<acmeman> version 2.00, the only available external source is B<apache>.
+of B<acmeman> version 1.05, the following sources are available:
+B<null>, B<apache>, and B<file>.
Consider the following configuration:
@@ -211,20 +213,24 @@ server (or whatever server is using the certificates). If more than one
B<postrenew> statements are defined, they will be run in sequence, in the
same order as they appeared in the configuration file.
-=item B<source=>I<ID> [I<LAYOUT>]
+=item B<source=>I<ID> [I<ARG>...]
Defines additional source of information. B<App::Acmeman> version 1.05
-is shipped with two sources: B<null> and B<apache>.
+is shipped with three sources: B<null>, B<apache>, and B<file>.
-The B<null> module is an empty source. Use it if all domains are described
-in the configuration file.
+The B<null> module is an empty source. Command line arguments are ignored.
+Use this source if all domains are described in the configuration file.
The B<apache> source module is the default. It scans B<httpd> configuration
-files as described in section B<APACHE>. The optional I<LAYOUT> argument
-defines the apache configuration layout. Allowed values are: B<debian>,
-B<slackware>, B<suse> and B<rh> (for Red Hat). If I<LAYOUT> is absent, it
+files as described in section B<APACHE>. One argument is allowed. If supplied,
+it defines the apache configuration layout. Allowed values are: B<debian>,
+B<slackware>, B<suse> and B<rh> (for Red Hat). Without arguments, the layout
will be autodetected.
+The B<file> source reads domain names from one or more disk files. A
+mandatory argument specifies the name of the directory where the files
+are located. This mode is suitable for use with B<haproxy> pattern files.
=item B<files=>I<NAME>
Identifies the B<[files]> section which describes how to create certificate
@@ -345,13 +351,29 @@ be replaced with the actual domain name. Default is B<$domain>.
-=head1 APACHE
+=head1 SOURCES
+=head2 null
+ [core]
+ source = null
+Declares empty source. This means that B<acmeman> will handle only domain
+names explicitly declared in the configuration file using the B<domain>
+=head2 apache
-This is the default mode. It assumes Apache httpd, version 2.4 or later
+ [core]
+ source = apache [LAYOUT]
+This is the default source. It assumes Apache httpd, version 2.4 or later
(although only minor changes are necessary to make it work with version 2.2).
-Four most popular layouts of Apache configuration files are supported:
-Debian, Slackware, SuSe, and Red Hat. A special directory should be
-configured for receiving ACME challenges.
+The optional I<LAYOUT> argument defines the layout of the apache configuration
+files. Allowed layout values are: B<debian>, B<slackware>, B<suse> and
+B<rh> (for Red Hat). If not supplied, the layout is determined automatically.
+A special directory should be configured for receiving ACME challenges.
The package provides two Apache macros: for serving ACME challenges and
declaring SSL virtual hosts.
@@ -363,7 +385,7 @@ predefined number of seconds (24 hours by default). If any of the
certificates were updated during the run, B<acmeman> will restart the
B<httpd> server.
-=head2 Setup
+=head3 Setup
To set up the necessary infrastructure, run B<acmeman --setup>. It will
create the configuration file B<httpd-letsencrypt.conf>, defining two
@@ -386,7 +408,7 @@ domain, and F<privkey.pem>, containing the private key for that domain.
The program will refuse to overwrite existing files B<httpd-letsencrypt.conf>,
unless given the B<--force> (B<-F>) option.
-=head2 Configuring SSL
+=head3 Configuring SSL
To declare that a virtual host needs SSL certificate, add the following
line to the Apache B<VirtualHost> block serving plain HTTP for that host:
@@ -465,6 +487,26 @@ will use the B<LetsEncryptSSL> macro to configure the correct certificate:
+=head2 file
+ [core]
+ source = file PATTERN [--ignore=RX] [--host=HOST]
+Domain names will be read from files matching I<PATTERN>. This argument
+can be either a valid globbing pattern or a directory name. In the latter
+case, the source module will read all files from that directory, except
+those whose names match the following perl regexp: C<^\.|~$|\.bak$|^#.*#$>.
+The default regexp can be overridden using the B<--ignore> (B<-i>) option.
+The input files must contain exactly one domain name per line. No empty
+lines or comments are allowed. The first domain name will become the B<CN>
+of the issued certificate. The rest of domain names will form alternative
+If the B<--host> (B<-h>) option is used, only one certificate will be
+issued. The I<HOST> will be used as its B<CN>. All the domain names read
+from the input files will form the list of its alternative names.
=head1 OPTIONS
=over 4
diff --git a/lib/App/Acmeman/Source/ b/lib/App/Acmeman/Source/
index 561c279..48a4010 100644
--- a/lib/App/Acmeman/Source/
+++ b/lib/App/Acmeman/Source/
@@ -5,22 +5,32 @@ use warnings;
use Carp;
use File::Spec;
use parent 'App::Acmeman::Source';
+use Getopt::Long qw(GetOptionsFromArray :config gnu_getopt no_ignore_case);
sub new {
my $class = shift;
my $pattern = shift || croak "file name or globbing pattern must be given";
my $ignore = '^\.|~$|\.bak$|^#.*#$';
+ my $host;
+ GetOptionsFromArray(\@_,
+ 'ignore|i=s' => \$ignore,
+ 'host|h=s' => \$host);
unless ($pattern =~ m{[][*?]}) {
$pattern =~ s{/$}{};
$pattern = File::Spec->catfile($pattern, '*');
- bless { pattern => $pattern, ignore => $ignore }, $class;
+ bless { pattern => $pattern,
+ ignore => $ignore,
+ host => $host }, $class;
sub scan {
my ($self) = @_;
$self->debug(1, "initializing file list from $self->{pattern}");
my $err = 0;
+ if ($self->{host}) {
+ $self->define_domain($self->{host});
+ }
foreach my $file (glob $self->{pattern}) {
next if $file =~ m{$self->{ignore}};
$err |= $self->load($file);
@@ -35,12 +45,16 @@ sub load {
or do {
$self->error("can't open $file: $!");
return 0;
- };
+ };
chomp(my @lines = <$fh>);
close $fh;
- my $cn = shift @lines;
- $self->define_domain($cn);
- $self->define_alias($cn, @lines);
+ if ($self->{host}) {
+ $self->define_alias($self->{host}, @lines);
+ } else {
+ my $cn = shift @lines;
+ $self->define_domain($cn);
+ $self->define_alias($cn, @lines);
+ }
return 1;

Return to:

Send suggestions and report system problems to the System administrator.