diff --git a/dyndns.pl b/dyndns.pl
index 5c02b01..96e4d42 100755
--- a/dyndns.pl
+++ b/dyndns.pl
@@ -26,12 +26,13 @@ use POSIX;
 use Net::DNS;
 use feature 'state';
 
+my $ConfigFile = 'optional';    # hardcoded, either optional, required or ignore
 
 ##############################
-# Configuration section
+# Configuration section (defaults, can be set in config file)
 my $DNSServer = '192.168.1.1';	# DNS Server to communicate with (use IP!)
 my $ExpandCNAMEs = 1;		# CNAME levels to expand (0 to disable)
-my $AllowDebugKey = 'on';	# Debuging, 'off' to disable, '' for always on
+my $AllowDebugKey = 'off';	# Debuging, 'off' to disable, '' for always on
 				# and other values to enable with debug= param.
 my $AuthMode = 'remote';	# either 'static', 'remote' or 'both'
 my $StaticSigner = '';		# required for AuthMode 'static' or 'both'
@@ -40,8 +41,9 @@ my $RequireRR = '';		# Require existing record of this type for upd.
 my $ExpireAfter = '1w';		# Expire time for registrations in minutes,
 				# hours, weeks or seconds. format: [0-9]+[mhws]?
 my @ReplaceRR = ('A', 'AAAA', 'TXT');	# Records types to replace in update
-my $UpdateTXT = 'Last DynDNS update on ';
-my $DeleteTXT = 'DynDNS cleared on ';
+my $RecordTTL = '1h';           # TTL for created records, format: [0-9]+[mhws]?
+my $UpdateTXT = 'Last DynDNS update on'; # if set add TXT with this+date on update
+my $DeleteTXT = 'DynDNS cleared on'; # if set add TXT with this+date on delete
 
 
 ##############################
@@ -60,16 +62,10 @@ sub is_ipv6 { return $_[0]=~/^([0-9a-fA-F]{0,4}(:|$)){3,8}/i; }
 sub periodSeconds($) {
   my ($number, $units) = ($_[0]=~/^(\d+)([smhdw])?$/);
   if($number && $units && $units cmp 's') {
-    $number *= 60;		# Convert to minutes
-    if($units cmp 'm') {
-      $number *= 60;		# Convert to hours
-      if($units cmp 'h') {
-	$number *= 24;		# Convert to days
-	if($units cmp 'd') {
-	  $number *= 7;		# Convert to weeks
-	}
-      }
-    }
+      $number *= ($units eq 'm') ? 60		# Seconds per minute
+		: ($units cmp 'h') ? 3600	# Seconds per hour
+		: ($units cmp 'd') ? 86400	# Seconds per day
+		: 604800;			# Seconds per week
   }
   return $number;
 }
@@ -163,6 +159,7 @@ sub get_authinfo($$) {
 sub DNS_Update($$$$$$$) {
   my ($dnsdomain, $dnshost, $ipv4, $ipv6, $signer, $key, $debug) = @_;
   my $dnsupdate = Net::DNS::Update->new($dnsdomain);
+  my $ttl = periodSeconds($RecordTTL);
 
   # If $RequireRR is set, ensure an records of specified type exist for the name
   $dnsupdate->push(pre => yxrrset("$dnshost. $RequireRR")) if($RequireRR);
@@ -173,13 +170,14 @@ sub DNS_Update($$$$$$$) {
   }
 
   # Add new A and AAAA record based on whether ipv4 and ipv6 address provided
-  $dnsupdate->push(update=>rr_add("$dnshost. 3600 A $ipv4")) if($ipv4);
-  $dnsupdate->push(update=>rr_add("$dnshost. 3600 AAAA $ipv6")) if($ipv6);
+  $dnsupdate->push(update=>rr_add("$dnshost. $ttl A $ipv4")) if($ipv4);
+  $dnsupdate->push(update=>rr_add("$dnshost. $ttl AAAA $ipv6")) if($ipv6);
 
-  # Always add a new TXT record with the timestamp of the last update
-  my $txt = ($ipv4 or $ipv6) ? $UpdateTXT : $DeleteTXT;
-  $dnsupdate->push(update=>rr_add($dnshost. '. 3600 TXT "' . $txt . localtime()
-				. '"'))	if($txt);
+  # Add a TXT record with the timestamp of the last update, if required
+  if (my $txt = ($ipv4 or $ipv6) ? $UpdateTXT : $DeleteTXT) {
+      my $timestamp = localtime();
+      $dnsupdate->push(update=>rr_add("$dnshost. $ttl TXT \"$txt $timestamp\""));
+  }
 
   # Sign the request with the signer and key
   $dnsupdate->sign_tsig($signer, $key);
@@ -327,23 +325,58 @@ sub handle_list($$$$$$) {
 my $cgi = CGI->new;
 
 ##############################
+# Load configuration, if desired
+if ($ConfigFile cmp 'ignore') {
+    my $CFGFile = $0;
+    $CFGFile =~ s/(\.pl)?$/.cfg/;
+    if (open (CONFIG, $CFGFile)) {
+        my %CONFIG = (
+            allow_debug_key => \$AllowDebugKey, dns_server      => \$DNSServer,
+            expand_cnames   => \$ExpandCNAMEs,  auth_mode       => \$AuthMode,
+            static_signer   => \$StaticSigner,  static_key      => \$StaticKey,
+            require_rr      => \$RequireRR,     replace_rr      => \@ReplaceRR,
+            update_txt      => \$UpdateTXT,     delete_txt      => \$DeleteTXT,
+            expire_after    => \$ExpireAfter,   record_ttl      => \$RecordTTL,
+        );
+
+        while (<CONFIG>) {
+            chomp; s/^\s+//; s/\s*(#.*)?$//;        # trim whitespace & comments
+            next unless length;                               # skip empty lines
+            my ($key, $value) = split(/\s*=\s*/, $_, 2);   # split key and value
+            my $dst = $CONFIG{$key};                 # get destination for value
+            if (ref $dst eq 'SCALAR') { $$dst = $value; }   # store scalar value
+            elsif (ref $dst eq 'CODE') { &$dst($value); } # call setter function
+            elsif (ref $dst cmp 'ARRAY') { die "Invalid $key in $CFGFile\n"; }
+            else  { @$dst = split(/\s*,\s*/, $value); }  # split and store array
+        }
+        close CONFIG;
+    } elsif ($ConfigFile eq 'required') {
+       die "unable to load configuration from $CFGFile: $!, aborting\n"
+    }
+}
+
+##############################
 # Validate Configuration
 my $CE = 'Configuration Error:';
-die "$CE \$AuthMode '$AuthMode' is unsupported must be remote, static or both\n"
+die "$CE ConfigFile must be optional, required or ignore, not '$ConfigFile'\n"
+	unless $ConfigFile=~/optional|required|ignore/;
+die "$CE AuthMode '$AuthMode' is unsupported must be remote, static or both\n"
 	unless $AuthMode=~/remote|static|both/;
-die "$CE \$StaticSigner must be set for \$AuthMode '$AuthMode'\n"
+die "$CE StaticSigner must be set for \$AuthMode '$AuthMode'\n"
 	unless ($StaticSigner or $AuthMode eq 'remote');
-die "$CE \$StaticKey must be set for \$AuthMode '$AuthMode'\n"
+die "$CE StaticKey must be set for \$AuthMode '$AuthMode'\n"
 	unless ($StaticKey or $AuthMode eq 'remote');
-die "$CE \$RequireRR is set to unsupported type '$RequireRR'\n"
+die "$CE RequireRR is set to unsupported type '$RequireRR'\n"
 	if ($RequireRR and not $DNS_label{$RequireRR});
-die "$CE \$ExpireAfter '$ExpireAfter' is not supported\n"
-	unless ($ExpireAfter=~/^\d+[smhw]$/);
-die "$CE \$UpdateTXT must be set when \$ExpireAfter is set\n"
+die "$CE RecordTTL '$RecordTTL' is not supported\n"
+	unless ($RecordTTL=~/^\d+[smhw]?$/);
+die "$CE ExpireAfter '$ExpireAfter' is not supported\n"
+	unless ($ExpireAfter=~/^\d+[smhw]?$/);
+die "$CE UpdateTXT must be set when \$ExpireAfter is set\n"
 	if($ExpireAfter and not $UpdateTXT);
 foreach my $rrtype (@ReplaceRR) {
-  die "$CE \$ReplaceRR contains unsupported type '$rrtype'\n"
-	unless ($DNS_label{$rrtype});
+  die "$CE ReplaceRR contains unsupported type '$rrtype'\n"
+	unless exists $DNS_label{$rrtype};
 }