diff --git a/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/application/nodeinfo/Nodeinfo2_0.kt b/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/application/nodeinfo/Nodeinfo2_0.kt
new file mode 100644
index 00000000..5809ec69
--- /dev/null
+++ b/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/application/nodeinfo/Nodeinfo2_0.kt
@@ -0,0 +1,3 @@
+package dev.usbharu.hideout.activitypub.application.nodeinfo
+
+data class Nodeinfo2_0()
\ No newline at end of file
diff --git a/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/config/ActivityPubSecurityConfig.kt b/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/config/ActivityPubSecurityConfig.kt
index b445a086..9dfbbe4c 100644
--- a/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/config/ActivityPubSecurityConfig.kt
+++ b/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/config/ActivityPubSecurityConfig.kt
@@ -24,6 +24,7 @@ class ActivityPubSecurityConfig {
             )
             authorizeHttpRequests {
                 authorize(GET, "/.well-known/**", permitAll)
+                authorize(GET, "/nodeinfo/**", permitAll)
                 authorize(GET, "/error", permitAll)
                 authorize(POST, "/inbox", permitAll)
                 authorize(POST, "/users/{username}/inbox", permitAll)
diff --git a/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/interfaces/wellknown/NodeinfoController.kt b/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/interfaces/wellknown/NodeinfoController.kt
new file mode 100644
index 00000000..c2c63e27
--- /dev/null
+++ b/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/interfaces/wellknown/NodeinfoController.kt
@@ -0,0 +1,23 @@
+package dev.usbharu.hideout.activitypub.interfaces.wellknown
+
+import dev.usbharu.hideout.core.config.ApplicationConfig
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RestController
+
+@RestController
+@RequestMapping("/.well-known")
+class NodeinfoController(private val applicationConfig: ApplicationConfig) {
+    @GetMapping("/nodeinfo", produces = ["application/json"])
+    suspend fun nodeinfo(): XRD = XRD(
+        listOf(
+            Link(
+                "http://nodeinfo.diaspora.software/ns/schema/2.1",
+                href = applicationConfig.url.resolve("/nodeinfo/2.1").toString()
+            ), Link(
+                "http://nodeinfo.diaspora.software/ns/schema/2.0",
+                href = applicationConfig.url.resolve("/nodeinfo/2.0").toString()
+            )
+        )
+    )
+}
\ No newline at end of file
diff --git a/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/interfaces/wellknown/XRD.kt b/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/interfaces/wellknown/XRD.kt
index e6617c3f..02a9792d 100644
--- a/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/interfaces/wellknown/XRD.kt
+++ b/hideout/hideout-activitypub/src/main/kotlin/dev/usbharu/hideout/activitypub/interfaces/wellknown/XRD.kt
@@ -24,8 +24,9 @@ data class XRD(
 data class Link(
     @JacksonXmlProperty(localName = "rel", isAttribute = true) val rel: String,
     @JsonInclude(JsonInclude.Include.NON_NULL)
-    @JacksonXmlProperty(localName = "template", isAttribute = true) val template: String?,
-    @JacksonXmlProperty(localName = "type", isAttribute = true) val type: String,
+    @JacksonXmlProperty(localName = "template", isAttribute = true) val template: String? = null,
     @JsonInclude(JsonInclude.Include.NON_NULL)
-    @JacksonXmlProperty(localName = "href", isAttribute = true) val href: String?,
+    @JacksonXmlProperty(localName = "type", isAttribute = true) val type: String? = null,
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    @JacksonXmlProperty(localName = "href", isAttribute = true) val href: String? = null,
 )
diff --git a/hideout/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SecurityConfig.kt b/hideout/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SecurityConfig.kt
index 9a1ea2da..97d62803 100644
--- a/hideout/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SecurityConfig.kt
+++ b/hideout/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/config/SecurityConfig.kt
@@ -90,7 +90,7 @@ class SecurityConfig {
                 authorize("/error", permitAll)
                 authorize("/auth/sign_in", permitAll)
                 authorize(GET, "/.well-known/**", permitAll)
-                authorize(GET, "/nodeinfo/2.0", permitAll)
+                authorize(GET, "/nodeinfo/**", permitAll)
 
                 authorize(GET, "/auth/sign_up", hasRole("ANONYMOUS"))
                 authorize(POST, "/auth/sign_up", permitAll)