diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..4a100ac
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,65 @@
+version: '3'
+
+volumes:
+  mariadb:
+    driver: local
+  cache:
+    driver: local
+
+networks:
+  db:
+    driver: bridge
+
+services:
+  mariadb:
+    image: mariadb:10.6
+    restart: always
+    environment:
+      MYSQL_ROOT_USER: root
+      MYSQL_ROOT_PASSWORD: mariadb
+      MYSQL_USER: pokerogue
+      MYSQL_PASSWORD: mariadb
+      MYSQL_DATABASE: pokeroguedb
+    expose:
+      - "3306"
+    volumes:
+      - mariadb:/var/lib/mysql
+      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
+    networks:
+      db:
+    healthcheck:
+      test: 'mysqladmin ping -h localhost -u$$MYSQL_ROOT_USER -p$$MYSQL_ROOT_PASSWORD' 
+      interval: 2s
+      timeout: 5s
+      retries: 5
+      start_period: 2s
+
+  phpmyadmin:
+    image: phpmyadmin
+    restart: always
+    expose:
+      - "40001"
+    ports:
+      - "40001:80"
+    environment:
+      - PMA_HOST=mariadb
+      - PMA_PORT=3306
+    networks:
+      db:
+
+  pokerogue:
+    image: golang
+    restart: always
+    working_dir: /app
+    volumes:
+      - .:/app
+      - cache:/go
+    ports:
+      - "8001:8001"
+    networks:
+      db:
+
+    command: go run pokerogue-server.go --addr=0.0.0.0:8001 --dbaddr=mariadb --dbuser=pokerogue --dbpass=mariadb --dbname=pokeroguedb --debug=true
+    depends_on:
+      mariadb:
+        condition: service_healthy
\ No newline at end of file
diff --git a/init.sql b/init.sql
new file mode 100644
index 0000000..5d3841e
--- /dev/null
+++ b/init.sql
@@ -0,0 +1,44 @@
+CREATE TABLE accounts (
+  uuid BINARY(16) NOT NULL PRIMARY KEY,
+  username VARCHAR(16) NOT NULL,
+  hash BINARY(32) NOT NULL,
+  salt BINARY(16) NOT NULL, 
+  registered DATETIME NOT NULL DEFAULT NOW(),
+  lastActivity DATETIME NOT NULL DEFAULT NOW(),
+  lastLoggedIn DATETIME NULL,
+  INDEX (lastActivity),
+  INDEX (username),
+  UNIQUE (username)
+);
+
+CREATE TABLE sessions (
+  token BINARY(32) NOT NULL PRIMARY KEY,
+  uuid BINARY(16) NOT NULL,
+  expire DATETIME NOT NULL,
+  FOREIGN KEY (uuid) REFERENCES accounts(uuid) ON DELETE CASCADE
+);
+
+CREATE TABLE dailyRuns (
+  seed VARCHAR(255) NOT NULL,
+  date DATE NOT NULL PRIMARY KEY
+);
+
+CREATE TABLE accountDailyRuns (
+  uuid BINARY(16) NOT NULL PRIMARY KEY,
+  date DATE NOT NULL,
+  score INT NOT NULL,
+  wave INT NOT NULL,
+  timestamp DATETIME,
+  FOREIGN KEY (date) REFERENCES dailyRuns(date),
+  FOREIGN KEY (uuid) REFERENCES accounts(uuid) ON DELETE CASCADE,
+  UNIQUE (uuid, date)
+);
+
+CREATE TABLE seedCompletions (
+  uuid BINARY(16) NOT NULL PRIMARY KEY,
+  seed VARCHAR(255) NOT NULL,
+  mode INT NOT NULL,
+  timestamp DATETIME NOT NULL DEFAULT NOW(),
+  FOREIGN KEY (uuid) REFERENCES accounts(uuid) ON DELETE CASCADE,
+  UNIQUE (seed, mode, uuid)
+);
diff --git a/pokerogue-server.go b/pokerogue-server.go
index f755e9b..135340d 100644
--- a/pokerogue-server.go
+++ b/pokerogue-server.go
@@ -15,7 +15,7 @@ func main() {
 	debug := flag.Bool("debug", false, "debug mode")
 
 	proto := flag.String("proto", "tcp", "protocol for api to use (tcp, unix)")
-	addr := flag.String("addr", "0.0.0.0", "network address for api to listen on")
+	addr := flag.String("addr", "0.0.0.0:8001", "network address for api to listen on")
 
 	dbuser := flag.String("dbuser", "pokerogue", "database username")
 	dbpass := flag.String("dbpass", "", "database password")
@@ -47,6 +47,8 @@ func main() {
 	api.ScheduleDailyRunRefresh()
 	api.InitDailyRun()
 
+	log.Printf("listening on %s %s", *proto, *addr)
+
 	err = http.Serve(listener, &api.Server{Debug: *debug})
 	if err != nil {
 		log.Fatalf("failed to create http server or server errored: %s", err)