diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/joinProtection/JoinProtection.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/joinProtection/JoinProtection.java
new file mode 100644
index 0000000..9bec6f9
--- /dev/null
+++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/joinProtection/JoinProtection.java
@@ -0,0 +1,43 @@
+package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.joinProtection;
+
+import eu.mhsl.craftattack.core.Main;
+import eu.mhsl.craftattack.core.appliance.Appliance;
+import net.kyori.adventure.util.Ticks;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Listener;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+public class JoinProtection extends Appliance {
+    private static final int resistanceDuration = 30;
+
+    private final List<UUID> protectedPlayers = new ArrayList<>();
+
+    public void addProtection(Player player) {
+        protectedPlayers.add(player.getUniqueId());
+        PotionEffect effect = new PotionEffect(PotionEffectType.RESISTANCE, Ticks.TICKS_PER_SECOND*resistanceDuration, 1);
+        player.addPotionEffect(effect, true);
+        Bukkit.getScheduler().runTaskLater(
+            Main.instance(),
+            () -> protectedPlayers.remove(player.getUniqueId()),
+            Ticks.TICKS_PER_SECOND*resistanceDuration
+        );
+    }
+
+    public void cancelEvent(Player player, Cancellable event) {
+        if(!protectedPlayers.contains(player.getUniqueId())) return;
+        event.setCancelled(true);
+    }
+
+    @Override
+    protected @NotNull List<Listener> listeners() {
+        return List.of(new JoinProtectionListener());
+    }
+}
diff --git a/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/joinProtection/JoinProtectionListener.java b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/joinProtection/JoinProtectionListener.java
new file mode 100644
index 0000000..5e94b80
--- /dev/null
+++ b/varo/src/main/java/eu/mhsl/craftattack/spawn/varo/appliances/metaGameplay/joinProtection/JoinProtectionListener.java
@@ -0,0 +1,49 @@
+package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.joinProtection;
+
+import eu.mhsl.craftattack.core.appliance.ApplianceListener;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.player.*;
+
+public class JoinProtectionListener extends ApplianceListener<JoinProtection> {
+    @EventHandler
+    public void onJoin(PlayerJoinEvent event) {
+        this.getAppliance().addProtection(event.getPlayer());
+    }
+
+    @EventHandler
+    public void onDamage(EntityDamageEvent event) {
+        if(!(event.getEntity() instanceof Player)) return;
+        this.getAppliance().cancelEvent((Player) event.getEntity(), event);
+    }
+
+    @EventHandler
+    public void onConsume(PlayerItemConsumeEvent event) {
+        this.getAppliance().cancelEvent(event.getPlayer(), event);
+    }
+
+    // flying is not enabled on the server
+    @EventHandler
+    public void onMove(PlayerMoveEvent event) {
+        if(!event.hasChangedPosition()) return;
+        this.getAppliance().cancelEvent(event.getPlayer(), event);
+    }
+
+    @EventHandler
+    public void onInteract(PlayerInteractEvent event) {
+        this.getAppliance().cancelEvent(event.getPlayer(), event);
+    }
+
+    @EventHandler
+    public void onBlockPlace(BlockPlaceEvent event) {
+        this.getAppliance().cancelEvent(event.getPlayer(), event);
+    }
+
+    @EventHandler
+    public void onBlockBreak(BlockBreakEvent event) {
+        this.getAppliance().cancelEvent(event.getPlayer(), event);
+    }
+}