Beispiel #1
0
func main() {
	app := cmd.NewAppShell("boulder-va", "Handles challenge validation")
	app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) {
		go cmd.DebugServer(c.VA.DebugAddr)

		go cmd.ProfileCmd("VA", stats)

		pc := &va.PortConfig{
			HTTPPort:  80,
			HTTPSPort: 443,
			TLSPort:   443,
		}
		if c.VA.PortConfig.HTTPPort != 0 {
			pc.HTTPPort = c.VA.PortConfig.HTTPPort
		}
		if c.VA.PortConfig.HTTPSPort != 0 {
			pc.HTTPSPort = c.VA.PortConfig.HTTPSPort
		}
		if c.VA.PortConfig.TLSPort != 0 {
			pc.TLSPort = c.VA.PortConfig.TLSPort
		}
		clk := clock.Default()
		sbc := newGoogleSafeBrowsing(c.VA.GoogleSafeBrowsing)
		vai := va.NewValidationAuthorityImpl(pc, sbc, stats, clk)
		dnsTimeout, err := time.ParseDuration(c.Common.DNSTimeout)
		cmd.FailOnError(err, "Couldn't parse DNS timeout")
		scoped := metrics.NewStatsdScope(stats, "VA", "DNS")
		dnsTries := c.VA.DNSTries
		if dnsTries < 1 {
			dnsTries = 1
		}
		if !c.Common.DNSAllowLoopbackAddresses {
			vai.DNSResolver = bdns.NewDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver}, scoped, clk, dnsTries)
		} else {
			vai.DNSResolver = bdns.NewTestDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver}, scoped, clk, dnsTries)
		}
		vai.UserAgent = c.VA.UserAgent
		vai.IssuerDomain = c.VA.IssuerDomain

		amqpConf := c.VA.AMQP
		rac, err := rpc.NewRegistrationAuthorityClient(clientName, amqpConf, stats)
		cmd.FailOnError(err, "Unable to create RA client")

		vai.RA = rac

		vas, err := rpc.NewAmqpRPCServer(amqpConf, c.VA.MaxConcurrentRPCServerRequests, stats)
		cmd.FailOnError(err, "Unable to create VA RPC server")
		rpc.NewValidationAuthorityServer(vas, vai)

		err = vas.Start(amqpConf)
		cmd.FailOnError(err, "Unable to run VA RPC server")
	}

	app.Run()
}
Beispiel #2
0
func main() {
	app := cmd.NewAppShell("boulder-va")
	app.Action = func(c cmd.Config) {
		stats, err := statsd.NewClient(c.Statsd.Server, c.Statsd.Prefix)
		cmd.FailOnError(err, "Couldn't connect to statsd")

		// Set up logging
		auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
		cmd.FailOnError(err, "Could not connect to Syslog")

		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		defer auditlogger.AuditPanic()

		blog.SetAuditLogger(auditlogger)

		go cmd.DebugServer(c.VA.DebugAddr)

		go cmd.ProfileCmd("VA", stats)

		vai := va.NewValidationAuthorityImpl(c.CA.TestMode)
		dnsTimeout, err := time.ParseDuration(c.Common.DNSTimeout)
		cmd.FailOnError(err, "Couldn't parse DNS timeout")
		vai.DNSResolver = core.NewDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver})
		vai.UserAgent = c.VA.UserAgent

		for {
			ch, err := cmd.AmqpChannel(c)
			cmd.FailOnError(err, "Could not connect to AMQP")

			closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))

			raRPC, err := rpc.NewAmqpRPCClient("VA->RA", c.AMQP.RA.Server, ch)
			cmd.FailOnError(err, "Unable to create RPC client")

			rac, err := rpc.NewRegistrationAuthorityClient(raRPC)
			cmd.FailOnError(err, "Unable to create RA client")

			vai.RA = &rac

			vas := rpc.NewAmqpRPCServer(c.AMQP.VA.Server, ch)

			err = rpc.NewValidationAuthorityServer(vas, &vai)
			cmd.FailOnError(err, "Unable to create VA server")

			auditlogger.Info(app.VersionString())

			cmd.RunUntilSignaled(auditlogger, vas, closeChan)
		}
	}

	app.Run()
}
Beispiel #3
0
func main() {
	app := cmd.NewAppShell("boulder-va", "Handles challenge validation")
	app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) {
		go cmd.DebugServer(c.VA.DebugAddr)

		go cmd.ProfileCmd("VA", stats)

		pc := &va.PortConfig{
			HTTPPort:  80,
			HTTPSPort: 443,
			TLSPort:   443,
		}
		if c.VA.PortConfig.HTTPPort != 0 {
			pc.HTTPPort = c.VA.PortConfig.HTTPPort
		}
		if c.VA.PortConfig.HTTPSPort != 0 {
			pc.HTTPSPort = c.VA.PortConfig.HTTPSPort
		}
		if c.VA.PortConfig.TLSPort != 0 {
			pc.TLSPort = c.VA.PortConfig.TLSPort
		}
		sbc := newGoogleSafeBrowsing(c.VA.GoogleSafeBrowsing)
		vai := va.NewValidationAuthorityImpl(pc, sbc, stats, clock.Default())
		dnsTimeout, err := time.ParseDuration(c.Common.DNSTimeout)
		cmd.FailOnError(err, "Couldn't parse DNS timeout")
		if !c.Common.DNSAllowLoopbackAddresses {
			vai.DNSResolver = core.NewDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver})
		} else {
			vai.DNSResolver = core.NewTestDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver})
		}
		vai.UserAgent = c.VA.UserAgent

		raRPC, err := rpc.NewAmqpRPCClient("VA->RA", c.AMQP.RA.Server, c, stats)
		cmd.FailOnError(err, "Unable to create RPC client")

		rac, err := rpc.NewRegistrationAuthorityClient(raRPC)
		cmd.FailOnError(err, "Unable to create RA client")

		vai.RA = &rac

		vas, err := rpc.NewAmqpRPCServer(c.AMQP.VA.Server, c.VA.MaxConcurrentRPCServerRequests, c)
		cmd.FailOnError(err, "Unable to create VA RPC server")
		rpc.NewValidationAuthorityServer(vas, vai)

		err = vas.Start(c)
		cmd.FailOnError(err, "Unable to run VA RPC server")
	}

	app.Run()
}
Beispiel #4
0
func main() {
	app := cmd.NewAppShell("boulder-va")
	app.Action = func(c cmd.Config) {
		stats, err := statsd.NewClient(c.Statsd.Server, c.Statsd.Prefix)
		cmd.FailOnError(err, "Couldn't connect to statsd")

		// Set up logging
		auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
		cmd.FailOnError(err, "Could not connect to Syslog")

		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		defer auditlogger.AuditPanic()

		blog.SetAuditLogger(auditlogger)

		go cmd.ProfileCmd("VA", stats)

		vai := va.NewValidationAuthorityImpl(c.CA.TestMode)

		for {
			ch := cmd.AmqpChannel(c.AMQP.Server)
			closeChan := ch.NotifyClose(make(chan *amqp.Error, 1))

			rac, err := rpc.NewRegistrationAuthorityClient(c.AMQP.RA.Client, c.AMQP.RA.Server, ch)
			cmd.FailOnError(err, "Unable to create RA client")

			vai.RA = &rac

			vas, err := rpc.NewValidationAuthorityServer(c.AMQP.VA.Server, ch, &vai)
			cmd.FailOnError(err, "Unable to create VA server")

			cmd.RunUntilSignaled(auditlogger, vas, closeChan)
		}
	}

	app.Run()
}
Beispiel #5
0
func main() {
	app := cmd.NewAppShell("boulder")
	app.Action = func(c cmd.Config) {
		stats, err := statsd.NewClient(c.Statsd.Server, c.Statsd.Prefix)
		cmd.FailOnError(err, "Couldn't connect to statsd")

		// Set up logging
		auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
		cmd.FailOnError(err, "Could not connect to Syslog")

		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		defer auditlogger.AuditPanic()

		blog.SetAuditLogger(auditlogger)

		// Run StatsD profiling
		go cmd.ProfileCmd("Monolith", stats)

		// Create the components
		wfe := wfe.NewWebFrontEndImpl()
		sa, err := sa.NewSQLStorageAuthority(c.SA.DBDriver, c.SA.DBName)
		cmd.FailOnError(err, "Unable to create SA")

		ra := ra.NewRegistrationAuthorityImpl()
		va := va.NewValidationAuthorityImpl(c.CA.TestMode)

		cadb, err := ca.NewCertificateAuthorityDatabaseImpl(c.CA.DBDriver, c.CA.DBName)
		cmd.FailOnError(err, "Failed to create CA database")

		ca, err := ca.NewCertificateAuthorityImpl(cadb, c.CA)
		cmd.FailOnError(err, "Unable to create CA")

		// Wire them up
		wfe.RA = &ra
		wfe.SA = sa
		wfe.Stats = stats
		wfe.SubscriberAgreementURL = c.SubscriberAgreementURL

		wfe.IssuerCert, err = cmd.LoadCert(c.CA.IssuerCert)
		cmd.FailOnError(err, fmt.Sprintf("Couldn't read issuer cert [%s]", c.CA.IssuerCert))

		ra.CA = ca
		ra.SA = sa
		ra.VA = &va
		va.RA = &ra
		ca.SA = sa

		// Set up paths
		wfe.BaseURL = c.WFE.BaseURL
		wfe.HandlePaths()

		// We need to tell the RA how to make challenge URIs
		// XXX: Better way to do this?  Part of improved configuration
		ra.AuthzBase = wfe.AuthzBase

		fmt.Fprintf(os.Stderr, "Server running, listening on %s...\n", c.WFE.ListenAddress)
		err = http.ListenAndServe(c.WFE.ListenAddress, HandlerTimer(http.DefaultServeMux, stats))
		cmd.FailOnError(err, "Error starting HTTP server")
	}

	app.Run()
}
Beispiel #6
0
func main() {
	app := cmd.NewAppShell("boulder-va", "Handles challenge validation")
	app.Action = func(c cmd.Config) {
		stats, err := statsd.NewClient(c.Statsd.Server, c.Statsd.Prefix)
		cmd.FailOnError(err, "Couldn't connect to statsd")

		// Set up logging
		auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
		cmd.FailOnError(err, "Could not connect to Syslog")
		auditlogger.Info(app.VersionString())

		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		defer auditlogger.AuditPanic()

		blog.SetAuditLogger(auditlogger)

		go cmd.DebugServer(c.VA.DebugAddr)

		go cmd.ProfileCmd("VA", stats)

		pc := &va.PortConfig{
			HTTPPort:  80,
			HTTPSPort: 443,
			TLSPort:   443,
		}
		if c.VA.PortConfig.HTTPPort != 0 {
			pc.HTTPPort = c.VA.PortConfig.HTTPPort
		}
		if c.VA.PortConfig.HTTPSPort != 0 {
			pc.HTTPSPort = c.VA.PortConfig.HTTPSPort
		}
		if c.VA.PortConfig.TLSPort != 0 {
			pc.TLSPort = c.VA.PortConfig.TLSPort
		}
		vai := va.NewValidationAuthorityImpl(pc, stats, clock.Default())
		dnsTimeout, err := time.ParseDuration(c.Common.DNSTimeout)
		cmd.FailOnError(err, "Couldn't parse DNS timeout")
		if !c.Common.DNSAllowLoopbackAddresses {
			vai.DNSResolver = core.NewDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver})
		} else {
			vai.DNSResolver = core.NewTestDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver})
		}
		vai.UserAgent = c.VA.UserAgent

		connectionHandler := func(srv *rpc.AmqpRPCServer) {
			raRPC, err := rpc.NewAmqpRPCClient("VA->RA", c.AMQP.RA.Server, srv.Channel, stats)
			cmd.FailOnError(err, "Unable to create RPC client")

			rac, err := rpc.NewRegistrationAuthorityClient(raRPC)
			cmd.FailOnError(err, "Unable to create RA client")

			vai.RA = &rac
		}

		vas, err := rpc.NewAmqpRPCServer(c.AMQP.VA.Server, connectionHandler, c.VA.MaxConcurrentRPCServerRequests)
		cmd.FailOnError(err, "Unable to create VA RPC server")
		rpc.NewValidationAuthorityServer(vas, vai)

		err = vas.Start(c)
		cmd.FailOnError(err, "Unable to run VA RPC server")
	}

	app.Run()
}
Beispiel #7
0
func main() {
	configFile := flag.String("config", "", "File path to the configuration file for this service")
	flag.Parse()
	if *configFile == "" {
		flag.Usage()
		os.Exit(1)
	}

	var c config
	err := cmd.ReadConfigFile(*configFile, &c)
	cmd.FailOnError(err, "Reading JSON config file into config structure")

	stats, logger := cmd.StatsAndLogging(c.Statsd, c.Syslog)
	scope := metrics.NewStatsdScope(stats, "VA")
	defer logger.AuditPanic()
	logger.Info(cmd.VersionString(clientName))

	pc := &cmd.PortConfig{
		HTTPPort:  80,
		HTTPSPort: 443,
		TLSPort:   443,
	}
	if c.VA.PortConfig.HTTPPort != 0 {
		pc.HTTPPort = c.VA.PortConfig.HTTPPort
	}
	if c.VA.PortConfig.HTTPSPort != 0 {
		pc.HTTPSPort = c.VA.PortConfig.HTTPSPort
	}
	if c.VA.PortConfig.TLSPort != 0 {
		pc.TLSPort = c.VA.PortConfig.TLSPort
	}

	sbc := newGoogleSafeBrowsing(c.VA.GoogleSafeBrowsing)

	var cdrClient *cdr.CAADistributedResolver
	if c.VA.CAADistributedResolver != nil {
		var err error
		cdrClient, err = cdr.New(
			scope,
			c.VA.CAADistributedResolver.Timeout.Duration,
			c.VA.CAADistributedResolver.MaxFailures,
			c.VA.CAADistributedResolver.Proxies,
			logger)
		cmd.FailOnError(err, "Failed to create CAADistributedResolver")
	}

	dnsTimeout, err := time.ParseDuration(c.Common.DNSTimeout)
	cmd.FailOnError(err, "Couldn't parse DNS timeout")
	dnsTries := c.VA.DNSTries
	if dnsTries < 1 {
		dnsTries = 1
	}
	clk := clock.Default()
	caaSERVFAILExceptions, err := bdns.ReadHostList(c.VA.CAASERVFAILExceptions)
	cmd.FailOnError(err, "Couldn't read CAASERVFAILExceptions file")
	var resolver bdns.DNSResolver
	if !c.Common.DNSAllowLoopbackAddresses {
		r := bdns.NewDNSResolverImpl(
			dnsTimeout,
			[]string{c.Common.DNSResolver},
			caaSERVFAILExceptions,
			scope,
			clk,
			dnsTries)
		resolver = r
	} else {
		r := bdns.NewTestDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver}, scope, clk, dnsTries)
		resolver = r
	}

	vai := va.NewValidationAuthorityImpl(
		pc,
		sbc,
		cdrClient,
		resolver,
		c.VA.UserAgent,
		c.VA.IssuerDomain,
		scope,
		clk,
		logger)

	amqpConf := c.VA.AMQP
	var grpcSrv *grpc.Server
	if c.VA.GRPC != nil {
		s, l, err := bgrpc.NewServer(c.VA.GRPC, scope)
		cmd.FailOnError(err, "Unable to setup VA gRPC server")
		err = bgrpc.RegisterValidationAuthorityGRPCServer(s, vai)
		cmd.FailOnError(err, "Unable to register VA gRPC server")
		go func() {
			err = s.Serve(l)
			cmd.FailOnError(err, "VA gRPC service failed")
		}()
		grpcSrv = s
	}

	vas, err := rpc.NewAmqpRPCServer(amqpConf, c.VA.MaxConcurrentRPCServerRequests, scope, logger)
	cmd.FailOnError(err, "Unable to create VA RPC server")

	go cmd.CatchSignals(logger, func() {
		vas.Stop()
		if grpcSrv != nil {
			grpcSrv.GracefulStop()
		}
	})

	err = rpc.NewValidationAuthorityServer(vas, vai)
	cmd.FailOnError(err, "Unable to setup VA RPC server")

	go cmd.DebugServer(c.VA.DebugAddr)
	go cmd.ProfileCmd(scope)

	err = vas.Start(amqpConf)
	cmd.FailOnError(err, "Unable to run VA RPC server")
}
Beispiel #8
0
func main() {
	app := cmd.NewAppShell("boulder-va", "Handles challenge validation")
	app.Action = func(c cmd.Config, stats metrics.Statter, logger blog.Logger) {
		go cmd.DebugServer(c.VA.DebugAddr)

		go cmd.ProfileCmd("VA", stats)

		pc := &cmd.PortConfig{
			HTTPPort:  80,
			HTTPSPort: 443,
			TLSPort:   443,
		}
		if c.VA.PortConfig.HTTPPort != 0 {
			pc.HTTPPort = c.VA.PortConfig.HTTPPort
		}
		if c.VA.PortConfig.HTTPSPort != 0 {
			pc.HTTPSPort = c.VA.PortConfig.HTTPSPort
		}
		if c.VA.PortConfig.TLSPort != 0 {
			pc.TLSPort = c.VA.PortConfig.TLSPort
		}
		var caaClient caaPB.CAACheckerClient
		if c.VA.CAAService != nil {
			conn, err := bgrpc.ClientSetup(c.VA.CAAService)
			cmd.FailOnError(err, "Failed to load credentials and create connection to service")
			caaClient = caaPB.NewCAACheckerClient(conn)
		}
		scoped := metrics.NewStatsdScope(stats, "VA", "DNS")
		sbc := newGoogleSafeBrowsing(c.VA.GoogleSafeBrowsing)
		var cdrClient *cdr.CAADistributedResolver
		if c.VA.CAADistributedResolver != nil {
			var err error
			cdrClient, err = cdr.New(
				scoped,
				c.VA.CAADistributedResolver.Timeout.Duration,
				c.VA.CAADistributedResolver.MaxFailures,
				c.VA.CAADistributedResolver.Proxies,
				logger,
			)
			cmd.FailOnError(err, "Failed to create CAADistributedResolver")
		}
		dnsTimeout, err := time.ParseDuration(c.Common.DNSTimeout)
		cmd.FailOnError(err, "Couldn't parse DNS timeout")
		dnsTries := c.VA.DNSTries
		if dnsTries < 1 {
			dnsTries = 1
		}
		clk := clock.Default()
		var resolver bdns.DNSResolver
		if !c.Common.DNSAllowLoopbackAddresses {
			r := bdns.NewDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver}, scoped, clk, dnsTries)
			r.LookupIPv6 = c.VA.LookupIPv6
			resolver = r
		} else {
			r := bdns.NewTestDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver}, scoped, clk, dnsTries)
			r.LookupIPv6 = c.VA.LookupIPv6
			resolver = r
		}
		vai := va.NewValidationAuthorityImpl(
			pc,
			sbc,
			caaClient,
			cdrClient,
			resolver,
			c.VA.UserAgent,
			c.VA.IssuerDomain,
			stats,
			clk,
			logger)

		amqpConf := c.VA.AMQP

		if c.VA.GRPC != nil {
			s, l, err := bgrpc.NewServer(c.VA.GRPC, metrics.NewStatsdScope(stats, "VA"))
			cmd.FailOnError(err, "Unable to setup VA gRPC server")
			err = bgrpc.RegisterValidationAuthorityGRPCServer(s, vai)
			cmd.FailOnError(err, "Unable to register VA gRPC server")
			go func() {
				err = s.Serve(l)
				cmd.FailOnError(err, "VA gRPC service failed")
			}()
		}

		vas, err := rpc.NewAmqpRPCServer(amqpConf, c.VA.MaxConcurrentRPCServerRequests, stats, logger)
		cmd.FailOnError(err, "Unable to create VA RPC server")
		err = rpc.NewValidationAuthorityServer(vas, vai)
		cmd.FailOnError(err, "Unable to setup VA RPC server")

		err = vas.Start(amqpConf)
		cmd.FailOnError(err, "Unable to run VA RPC server")
	}

	app.Run()
}
Beispiel #9
0
func main() {
	app := cmd.NewAppShell("boulder")
	app.Action = func(c cmd.Config) {
		stats, err := statsd.NewClient(c.Statsd.Server, c.Statsd.Prefix)
		cmd.FailOnError(err, "Couldn't connect to statsd")

		// Set up logging
		auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats)
		cmd.FailOnError(err, "Could not connect to Syslog")

		// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
		defer auditlogger.AuditPanic()

		blog.SetAuditLogger(auditlogger)

		// Run StatsD profiling
		go cmd.ProfileCmd("Monolith", stats)

		// Create the components
		wfei, err := wfe.NewWebFrontEndImpl()
		cmd.FailOnError(err, "Unable to create WFE")
		sa, err := sa.NewSQLStorageAuthority(c.SA.DBDriver, c.SA.DBName)
		cmd.FailOnError(err, "Unable to create SA")
		sa.SetSQLDebug(c.SQL.SQLDebug)

		ra := ra.NewRegistrationAuthorityImpl()

		va := va.NewValidationAuthorityImpl(c.CA.TestMode)
		dnsTimeout, err := time.ParseDuration(c.VA.DNSTimeout)
		cmd.FailOnError(err, "Couldn't parse DNS timeout")
		va.DNSResolver = core.NewDNSResolver(dnsTimeout, []string{c.VA.DNSResolver})
		va.UserAgent = c.VA.UserAgent

		cadb, err := ca.NewCertificateAuthorityDatabaseImpl(c.CA.DBDriver, c.CA.DBName)
		cmd.FailOnError(err, "Failed to create CA database")

		ca, err := ca.NewCertificateAuthorityImpl(cadb, c.CA, c.Common.IssuerCert)
		cmd.FailOnError(err, "Unable to create CA")

		if c.SQL.CreateTables {
			err = sa.CreateTablesIfNotExists()
			cmd.FailOnError(err, "Failed to create SA tables")

			err = cadb.CreateTablesIfNotExists()
			cmd.FailOnError(err, "Failed to create CA tables")
		}

		// Wire them up
		wfei.RA = &ra
		wfei.SA = sa
		wfei.Stats = stats
		wfei.SubscriberAgreementURL = c.SubscriberAgreementURL

		wfei.IssuerCert, err = cmd.LoadCert(c.Common.IssuerCert)
		cmd.FailOnError(err, fmt.Sprintf("Couldn't read issuer cert [%s]", c.Common.IssuerCert))

		ra.CA = ca
		ra.SA = sa
		ra.VA = &va
		va.RA = &ra
		ca.SA = sa

		// Set up paths
		ra.AuthzBase = c.Common.BaseURL + wfe.AuthzPath
		wfei.BaseURL = c.Common.BaseURL
		wfei.HandlePaths()

		ra.MaxKeySize = c.Common.MaxKeySize
		ca.MaxKeySize = c.Common.MaxKeySize

		auditlogger.Info(app.VersionString())

		fmt.Fprintf(os.Stderr, "Server running, listening on %s...\n", c.WFE.ListenAddress)
		err = http.ListenAndServe(c.WFE.ListenAddress, HandlerTimer(http.DefaultServeMux, stats))
		cmd.FailOnError(err, "Error starting HTTP server")
	}

	app.Run()
}