diff --git a/modules/infrastructure/healthchecksio.tf b/modules/infrastructure/healthchecksio.tf
index c8de994..789cc3b 100644
--- a/modules/infrastructure/healthchecksio.tf
+++ b/modules/infrastructure/healthchecksio.tf
@@ -28,7 +28,7 @@ resource "healthchecksio_check" "backup" {
   ]
 
   timeout = 86400
-  grace = 1800
+  grace = 3600
 }
 
 resource "healthchecksio_check" "healthcheck" {
diff --git a/modules/infrastructure/variables.tf b/modules/infrastructure/variables.tf
index 8889653..4f5918d 100644
--- a/modules/infrastructure/variables.tf
+++ b/modules/infrastructure/variables.tf
@@ -24,7 +24,7 @@ variable "services" {
     })))
     ports = optional(list(object({
       description = string
-      port = number
+      port = string
       protocol = string
       type = string
     })))
diff --git a/playbooks/roles/factorio/tasks/main.yml b/playbooks/roles/factorio/tasks/main.yml
new file mode 100644
index 0000000..a8c07aa
--- /dev/null
+++ b/playbooks/roles/factorio/tasks/main.yml
@@ -0,0 +1,36 @@
+---
+- name: Set common facts
+  ansible.builtin.import_tasks: tasks/set-default-facts.yml
+
+- name: Deploy {{ role_name }}
+  vars:
+    svc: "{{ factorio_svc }}"
+    env: "{{ factorio_env }}"
+    json: "{{ factorio_json }}"
+    compose: "{{ factorio_compose }}"
+  block:
+    - name: Import prepare tasks for common service
+      ansible.builtin.import_tasks: tasks/prepare-common-service.yml
+
+    - name: Set config path
+      ansible.builtin.set_fact:
+        config_path: "{{ (service_path, 'config') | path_join }}"
+    - name: Create config directory
+      ansible.builtin.file:
+        path: "{{ config_path }}"
+        state: directory
+        mode: "0755"
+        owner: "{{ factorio_uid }}"
+        group: "{{ factorio_gid }}"
+      become: true
+    - name: Template the server settings
+      ansible.builtin.template:
+        src: "json.j2"
+        dest: "{{ (config_path, 'server-settings.json') | path_join }}"
+        mode: "0644"
+        owner: "{{ factorio_uid }}"
+        group: "{{ factorio_gid }}"
+      become: true
+
+    - name: Import start tasks for common service
+      ansible.builtin.import_tasks: tasks/start-common-service.yml
diff --git a/playbooks/roles/factorio/vars/main.yml b/playbooks/roles/factorio/vars/main.yml
new file mode 100644
index 0000000..68c4187
--- /dev/null
+++ b/playbooks/roles/factorio/vars/main.yml
@@ -0,0 +1,66 @@
+---
+factorio_port: 34197
+factorio_uid: 845
+factorio_gid: 845
+
+factorio_svc:
+  domain: "{{ all_services | service_get_domain(role_name) }}"
+  port: "{{ factorio_port }}"
+
+factorio_env:
+  PORT: "{{ factorio_port }}"
+  USERNAME: "{{ vault_factorio.username }}"
+  TOKEN: "{{ vault_factorio.token }}"
+
+factorio_json:
+  name: "StammtischOnAutomation"
+  description: "Private Server"
+  tags: []
+
+  max_players: 0
+  visibility:
+    public: true
+    lan: true
+
+  username: "{{ vault_factorio.username }}"
+  password: ""
+  token: "{{ vault_factorio.token }}"
+
+  game_password: "{{ vault_factorio.game_password }}"
+  require_user_verification: true
+
+  max_upload_in_kilobytes_per_second: 0
+  max_upload_slots: 0
+  max_heartbeats_per_second: 60
+  ignore_player_limit_for_returning_players: true
+  allow_commands: "admins-only"
+  autosave_interval: 10
+  autosave_slots: 6
+  afk_autokick_interval: 60
+
+  auto_pause: true
+  auto_pause_when_players_connect: false
+  only_admins_can_pause_the_game: true
+  autosave_only_on_server: true
+  non_blocking_saving: false
+
+  minimum_segment_size: 25
+  minimum_segment_size_peer_count: 20
+  maximum_segment_size: 100
+  maximum_segment_size_peer_count: 10
+
+
+factorio_compose:
+  watchtower: false
+  image: "factoriotools/factorio:stable"
+  volumes:
+    - data:/factorio
+    - ./config:/factorio/config
+  file:
+    services:
+      app:
+        ports:
+          - "{{ factorio_port }}:{{ factorio_port }}/udp"
+          - "27015:27015/tcp"
+    volumes:
+      data:
diff --git a/services.auto.tfvars b/services.auto.tfvars
index a70ee05..c2bb2a7 100644
--- a/services.auto.tfvars
+++ b/services.auto.tfvars
@@ -128,6 +128,43 @@ services = {
     s3 = false
   },
 
+  "factorio" = {
+    host = "node001"
+    dns = [{
+      domain = "factorio.serguzim.me"
+    }]
+    backup = [{
+      name = "factorio_data"
+      type = "docker"
+    }]
+    monitoring = {
+      url = "https://multiplayer.factorio.com/get-game-details/49.13.212.188:34197"
+      group = "4-services"
+      interval = "5m"
+      conditions = [
+        "DEFAULT",
+        "[BODY].name == StammtischOnAutomation"
+      ]
+    }
+    ports = [
+      {
+        description = "Game port for factorio"
+        port = 34197
+        protocol = "udp"
+        type = "firewall"
+      },
+      {
+        description = "RCON port for factorio"
+        port = 27015
+        protocol = "tcp"
+        type = "firewall"
+      }
+    ]
+    auth = false
+    database = false
+    s3 = false
+  }
+
   "forgejo" = {
     host = "node001"
     dns = [{
diff --git a/variables.tf b/variables.tf
index acaf01e..e25622f 100644
--- a/variables.tf
+++ b/variables.tf
@@ -153,7 +153,7 @@ variable "services" {
     }))
     ports = optional(list(object({
       description = string
-      port = number
+      port = string
       protocol = string
       type = string
     })))