diff --git a/cmd/gqgmcd/main.go b/cmd/gqgmcd/main.go
index 13bb01766d4eed72f38ebaa37686fb50b67be6d1..d759f3474c744506efad790e516cf1dafdcbb6c5 100644
--- a/cmd/gqgmcd/main.go
+++ b/cmd/gqgmcd/main.go
@@ -8,143 +8,37 @@
 package main
 
 import (
-	"flag"
-	"html/template"
+	flag "github.com/spf13/pflag"
 	"log"
 	"net/http"
-	"path"
-	"time"
 
-	"github.com/prometheus/client_golang/prometheus"
-	"github.com/prometheus/client_golang/prometheus/promhttp"
+	"gitlab.com/lyda/gqgmc/config"
 	"gitlab.com/lyda/gqgmc/devices/geiger"
+	"gitlab.com/lyda/gqgmc/server/metrics"
+	"gitlab.com/lyda/gqgmc/server/pages"
 )
 
-var addr = flag.String("listen-address", ":8080", "Address for HTTP requests.")
-var device = flag.String("device", "/dev/gqgmc", "Device for Geiger Counter.")
-var model = flag.String("model", "gqgmc", "Model of Geiger Counter.")
-var templateDir = flag.String("template-dir", "templates", "Template directory.")
-var staticDir = flag.String("static-dir", "static", "Static files directory.")
-
-type indexPage struct {
-	Model   string
-	Version string
-	Serial  string
-	Volts   int16
-	CPM     uint16
-	CPS     uint16
-}
-
-var gc geiger.Counter
-var indexPg indexPage
-
-func indexHandler(w http.ResponseWriter, r *http.Request) {
-	indexPg.CPM, _ = gc.GetCPM()
-	indexPg.Volts, _ = gc.Volts()
-	t, err := template.ParseFiles(path.Join(*templateDir, "index.html"))
-	if err != nil {
-		log.Printf("Template error: %s\n", err)
-	}
-	t.Execute(w, &indexPg)
-}
-
-func staticHandler(w http.ResponseWriter, r *http.Request) {
-	staticFile := path.Join(*staticDir, path.Base(r.URL.Path))
-	http.ServeFile(w, r, staticFile)
-}
-
-// Metrics collects the metrics.
-type Metrics struct {
-	CPM,
-	CPS,
-	Volts,
-	Errors *prometheus.HistogramVec
-}
-
-var metrics = &Metrics{
-	CPM: prometheus.NewHistogramVec(prometheus.HistogramOpts{
-		Namespace: "gqgmc",
-		Subsystem: "geiger",
-		Name:      "cpm",
-		Help:      "CPM readings",
-		Buckets:   []float64{50, 99, 999, 1999},
-	}, []string{"serial"}),
-	CPS: prometheus.NewHistogramVec(prometheus.HistogramOpts{
-		Namespace: "gqgmc",
-		Subsystem: "geiger",
-		Name:      "cps",
-		Help:      "CPS readings",
-		Buckets:   []float64{1, 2, 16, 33},
-	}, []string{"serial"}),
-	Volts: prometheus.NewHistogramVec(prometheus.HistogramOpts{
-		Namespace: "gqgmc",
-		Subsystem: "power",
-		Name:      "volts",
-		Help:      "Voltage readings",
-		Buckets:   []float64{22, 27, 42, 50},
-	}, []string{"serial"}),
-	Errors: prometheus.NewHistogramVec(prometheus.HistogramOpts{
-		Namespace: "gqgmc",
-		Subsystem: "sys",
-		Name:      "errors",
-		Help:      "Error counts",
-		Buckets:   []float64{1, 10, 100},
-	}, []string{"serial"}),
-}
-
-func gatherMetrics() {
-	var (
-		cpm, cps uint16
-		volts    int16
-		errCt    float64
-		err      error
-	)
-
-	for {
-		if cpm, err = gc.GetCPM(); err != nil {
-			log.Printf("gc.GetCPM error: %s\n", err)
-			errCt++
-		} else {
-			metrics.CPM.WithLabelValues(gc.Serial()).Observe(float64(cpm))
-		}
-		if cps, err = gc.GetCPS(); err != nil {
-			log.Printf("gc.GetCPS error: %s\n", err)
-			errCt++
-		} else {
-			metrics.CPS.WithLabelValues(gc.Serial()).Observe(float64(cps))
-		}
-		if volts, err = gc.Volts(); err != nil {
-			log.Printf("gc.Volts error: %s\n", err)
-			errCt++
-		} else {
-			metrics.Volts.WithLabelValues(gc.Serial()).Observe(float64(volts))
-		}
-		metrics.Errors.WithLabelValues(gc.Serial()).Observe(errCt)
-		time.Sleep(5 * time.Second)
-	}
-}
+var addr = flag.String("listen-address", ":8080", "Address for HTTP requests")
+var device = flag.String("device", "/dev/gqgmc", "Device for Geiger Counter")
+var model = flag.String("model", "gqgmc", "Model of Geiger Counter")
+var templateDir = flag.String("template-dir", "templates", "Template directory")
+var staticDir = flag.String("static-dir", "static", "Static files directory")
+var cfg = flag.String("config", "gqgmc.conf", "Config file")
 
 func main() {
 	flag.Parse()
+	c, err := config.ReadConfig(*cfg)
+	if err != nil {
+		log.Printf("Couldn't read config: %s\n", err)
+		return
+	}
 
-	gc, _ = geiger.New(geiger.Config{Model: *model, Device: *device})
-
-	indexPg.Model = gc.Model()
-	indexPg.Version = gc.Version()
-	indexPg.Serial = gc.Serial()
-
-	prometheus.MustRegister(metrics.CPM)
-	prometheus.MustRegister(metrics.CPS)
-	prometheus.MustRegister(metrics.Volts)
-	prometheus.MustRegister(metrics.Errors)
+	gc, _ := geiger.New(geiger.Config{Model: c.Model, Device: c.Device})
 
-	http.HandleFunc("/", indexHandler)
-	http.HandleFunc("/favicon.ico", staticHandler)
-	http.HandleFunc("/robots.txt", staticHandler)
-	http.HandleFunc("/humans.txt", staticHandler)
-	http.Handle("/metrics", promhttp.Handler())
-	http.Handle("/static", http.StripPrefix("/static/", http.FileServer(http.Dir(*staticDir))))
+	p := pages.New(gc, c.StaticDir, c.TemplateDir)
+	p.Register()
+	m := metrics.Register(gc)
 
-	go gatherMetrics()
+	go m.Gather()
 	log.Fatal(http.ListenAndServe(*addr, nil))
 }
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000000000000000000000000000000000000..22a0be3865ff497460b6dac3d3eb345bd996565d
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,45 @@
+//
+// config.go
+// Copyright (C) 2017 kevin <kevin@phrye.com>
+//
+// Distributed under terms of the GPL license.
+//
+
+package config
+
+import (
+	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
+)
+
+// Config for storing configuration.
+type Config struct {
+	ListenAddress string `mapstructure:"listen_address"`
+	Device        string `mapstructure:"device"`
+	Model         string `mapstructure:"model"`
+	TemplateDir   string `mapstructure:"template_dir"`
+	StaticDir     string `mapstructure:"static_dir"`
+}
+
+func setDefaults() {
+	viper.BindPFlag("listen_address", pflag.Lookup("listen-address"))
+	viper.BindPFlag("device", pflag.Lookup("device"))
+	viper.BindPFlag("model", pflag.Lookup("model"))
+	viper.BindPFlag("template_dir", pflag.Lookup("template-dir"))
+	viper.BindPFlag("static_dir", pflag.Lookup("static-dir"))
+}
+
+// ReadConfig reads the client configuration from a file into a Config struct.
+func ReadConfig(cfg string) (*Config, error) {
+	setDefaults()
+	viper.SetConfigFile(cfg)
+	viper.SetConfigType("hcl")
+	if err := viper.ReadInConfig(); err != nil {
+		return nil, err
+	}
+	c := &Config{}
+	if err := viper.Unmarshal(c); err != nil {
+		return nil, err
+	}
+	return c, nil
+}
diff --git a/server/metrics/metrics.go b/server/metrics/metrics.go
new file mode 100644
index 0000000000000000000000000000000000000000..2f479bcfef854d98b778c68e617ddca5cc8ee866
--- /dev/null
+++ b/server/metrics/metrics.go
@@ -0,0 +1,103 @@
+//
+// metrics.go
+// Copyright (C) 2017 kevin <kevin@ie.suberic.net>
+//
+// Distributed under terms of the MIT license.
+//
+
+package metrics
+
+import (
+	"log"
+	"net/http"
+	"time"
+
+	"github.com/prometheus/client_golang/prometheus"
+	"github.com/prometheus/client_golang/prometheus/promhttp"
+	"gitlab.com/lyda/gqgmc/devices/geiger"
+)
+
+// Metrics collects the metrics.
+type Metrics struct {
+	gc geiger.Counter
+	cpm,
+	cps,
+	volts,
+	errs *prometheus.HistogramVec
+}
+
+// Register metrics and metrics page.
+func Register(gc geiger.Counter) *Metrics {
+	var metrics = &Metrics{
+		gc: gc,
+		cpm: prometheus.NewHistogramVec(prometheus.HistogramOpts{
+			Namespace: "gqgmc",
+			Subsystem: "geiger",
+			Name:      "cpm",
+			Help:      "CPM readings",
+			Buckets:   []float64{50, 99, 999, 1999},
+		}, []string{"serial"}),
+		cps: prometheus.NewHistogramVec(prometheus.HistogramOpts{
+			Namespace: "gqgmc",
+			Subsystem: "geiger",
+			Name:      "cps",
+			Help:      "CPS readings",
+			Buckets:   []float64{1, 2, 16, 33},
+		}, []string{"serial"}),
+		volts: prometheus.NewHistogramVec(prometheus.HistogramOpts{
+			Namespace: "gqgmc",
+			Subsystem: "power",
+			Name:      "volts",
+			Help:      "Voltage readings",
+			Buckets:   []float64{22, 27, 42, 50},
+		}, []string{"serial"}),
+		errs: prometheus.NewHistogramVec(prometheus.HistogramOpts{
+			Namespace: "gqgmc",
+			Subsystem: "sys",
+			Name:      "errors",
+			Help:      "Error counts",
+			Buckets:   []float64{1, 10, 100},
+		}, []string{"serial"}),
+	}
+	prometheus.MustRegister(metrics.cpm)
+	prometheus.MustRegister(metrics.cps)
+	prometheus.MustRegister(metrics.volts)
+	prometheus.MustRegister(metrics.errs)
+
+	http.Handle("/metrics", promhttp.Handler())
+
+	return metrics
+}
+
+// Gather loop to gather metrics
+func (m *Metrics) Gather() {
+	var (
+		cpm, cps uint16
+		volts    int16
+		errCt    float64
+		err      error
+	)
+
+	for {
+		if cpm, err = m.gc.GetCPM(); err != nil {
+			log.Printf("gc.GetCPM error: %s\n", err)
+			errCt++
+		} else {
+			m.cpm.WithLabelValues(m.gc.Serial()).Observe(float64(cpm))
+		}
+		if cps, err = m.gc.GetCPS(); err != nil {
+			log.Printf("gc.GetCPS error: %s\n", err)
+			errCt++
+		} else {
+			m.cps.WithLabelValues(m.gc.Serial()).Observe(float64(cps))
+		}
+		if volts, err = m.gc.Volts(); err != nil {
+			log.Printf("gc.Volts error: %s\n", err)
+			errCt++
+		} else {
+			m.volts.WithLabelValues(m.gc.Serial()).Observe(float64(volts))
+		}
+		m.errs.WithLabelValues(m.gc.Serial()).Observe(errCt)
+		time.Sleep(5 * time.Second)
+	}
+}
diff --git a/server/pages/pages.go b/server/pages/pages.go
new file mode 100644
index 0000000000000000000000000000000000000000..ef62b6b37c0b207ba20e717978053b2ca8f4ab52
--- /dev/null
+++ b/server/pages/pages.go
@@ -0,0 +1,67 @@
+//
+// pages.go
+// Copyright (C) 2017 kevin <kevin@ie.suberic.net>
+//
+// Distributed under terms of the MIT license.
+//
+
+package pages
+
+import (
+	"html/template"
+	"log"
+	"net/http"
+	"path"
+
+	"gitlab.com/lyda/gqgmc/devices/geiger"
+)
+
+// Pages where data for pages goes
+type Pages struct {
+	gc geiger.Counter
+	staticDir,
+	templateDir string
+}
+
+type indexPage struct {
+	Model   string
+	Version string
+	Serial  string
+	Volts   int16
+	CPM     uint16
+}
+
+// New create new Pages.
+func New(gc geiger.Counter, staticDir, templateDir string) Pages {
+	return Pages{gc: gc, staticDir: staticDir, templateDir: templateDir}
+}
+
+// Register pages.
+func (p Pages) Register() {
+	http.HandleFunc("/", p.indexHandler)
+	http.HandleFunc("/favicon.ico", p.staticHandler)
+	http.HandleFunc("/robots.txt", p.staticHandler)
+	http.HandleFunc("/humans.txt", p.staticHandler)
+	http.Handle("/static", http.StripPrefix("/static/", http.FileServer(http.Dir(p.staticDir))))
+}
+
+func (p Pages) indexHandler(w http.ResponseWriter, r *http.Request) {
+	var indexPg indexPage
+
+	indexPg.CPM, _ = p.gc.GetCPM()
+	indexPg.Volts, _ = p.gc.Volts()
+	indexPg.Model = p.gc.Model()
+	indexPg.Version = p.gc.Version()
+	indexPg.Serial = p.gc.Serial()
+
+	t, err := template.ParseFiles(path.Join(p.templateDir, "index.html"))
+	if err != nil {
+		log.Printf("Template error: %s\n", err)
+	}
+	t.Execute(w, &indexPg)
+}
+
+func (p Pages) staticHandler(w http.ResponseWriter, r *http.Request) {
+	staticFile := path.Join(p.staticDir, path.Base(r.URL.Path))
+	http.ServeFile(w, r, staticFile)
+}