From 3b89a8bfa692cfeb9b71e7489bf493c40ab6a701 Mon Sep 17 00:00:00 2001
From: naskya <m@naskya.net>
Date: Sat, 20 Apr 2024 02:07:08 +0900
Subject: [PATCH] refactor (backend): port config loader to backend-rs
 completely

---
 packages/backend-rs/index.d.ts                |  70 +++++-
 packages/backend-rs/index.js                  |   6 +-
 packages/backend-rs/src/config/environment.rs |   2 +-
 packages/backend-rs/src/config/server.rs      | 201 +++++++++++++++++-
 packages/backend-rs/src/database/mod.rs       |  12 +-
 packages/backend-rs/src/misc/convert_host.rs  |   8 +-
 packages/backend/src/boot/index.ts            |   2 +-
 packages/backend/src/boot/master.ts           |  30 +--
 packages/backend/src/boot/worker.ts           |   2 +-
 packages/backend/src/config.ts                |   4 +
 packages/backend/src/config/index.ts          |   5 -
 packages/backend/src/config/load.ts           |  89 --------
 packages/backend/src/config/types.ts          |  20 --
 packages/backend/src/const.ts                 |   2 +-
 packages/backend/src/db/postgre.ts            |   2 +-
 packages/backend/src/db/redis.ts              |   2 +-
 packages/backend/src/mfm/to-html.ts           |   2 +-
 packages/backend/src/misc/captcha.ts          |   2 +-
 packages/backend/src/misc/download-url.ts     |   2 +-
 packages/backend/src/misc/fetch.ts            |   2 +-
 packages/backend/src/misc/populate-emojis.ts  |   2 +-
 .../src/models/repositories/drive-file.ts     |   2 +-
 .../backend/src/models/repositories/user.ts   |   2 +-
 .../src/models/schema/federation-instance.ts  |   2 +-
 packages/backend/src/queue/index.ts           |   6 +-
 packages/backend/src/queue/initialize.ts      |   2 +-
 .../processors/db/export-custom-emojis.ts     |   2 +-
 .../src/queue/processors/webhook-deliver.ts   |   2 +-
 packages/backend/src/queue/queues.ts          |   2 +-
 .../src/remote/activitypub/check-fetch.ts     |   2 +-
 .../src/remote/activitypub/db-resolver.ts     |   2 +-
 .../remote/activitypub/kernel/flag/index.ts   |   2 +-
 .../src/remote/activitypub/renderer/accept.ts |   2 +-
 .../src/remote/activitypub/renderer/add.ts    |   2 +-
 .../remote/activitypub/renderer/announce.ts   |   2 +-
 .../src/remote/activitypub/renderer/block.ts  |   2 +-
 .../src/remote/activitypub/renderer/create.ts |   2 +-
 .../src/remote/activitypub/renderer/delete.ts |   2 +-
 .../src/remote/activitypub/renderer/emoji.ts  |   2 +-
 .../src/remote/activitypub/renderer/flag.ts   |   2 +-
 .../activitypub/renderer/follow-relay.ts      |   2 +-
 .../activitypub/renderer/follow-user.ts       |   2 +-
 .../src/remote/activitypub/renderer/follow.ts |   2 +-
 .../remote/activitypub/renderer/hashtag.ts    |   2 +-
 .../src/remote/activitypub/renderer/index.ts  |   2 +-
 .../src/remote/activitypub/renderer/key.ts    |   2 +-
 .../src/remote/activitypub/renderer/like.ts   |   2 +-
 .../remote/activitypub/renderer/mention.ts    |   2 +-
 .../src/remote/activitypub/renderer/note.ts   |   2 +-
 .../src/remote/activitypub/renderer/person.ts |   2 +-
 .../remote/activitypub/renderer/question.ts   |   2 +-
 .../src/remote/activitypub/renderer/read.ts   |   2 +-
 .../src/remote/activitypub/renderer/reject.ts |   2 +-
 .../src/remote/activitypub/renderer/remove.ts |   2 +-
 .../src/remote/activitypub/renderer/undo.ts   |   2 +-
 .../src/remote/activitypub/renderer/update.ts |   2 +-
 .../src/remote/activitypub/renderer/vote.ts   |   2 +-
 .../backend/src/remote/activitypub/request.ts |   2 +-
 .../src/remote/activitypub/resolver.ts        |   2 +-
 packages/backend/src/remote/resolve-user.ts   |   2 +-
 packages/backend/src/server/activitypub.ts    |   2 +-
 .../src/server/activitypub/featured.ts        |   2 +-
 .../src/server/activitypub/followers.ts       |   2 +-
 .../src/server/activitypub/following.ts       |   2 +-
 .../backend/src/server/activitypub/outbox.ts  |   2 +-
 packages/backend/src/server/api/2fa.ts        |   2 +-
 .../backend/src/server/api/common/signin.ts   |   2 +-
 .../backend/src/server/api/common/signup.ts   |   2 +-
 .../api/endpoints/admin/accounts/hosted.ts    |   2 +-
 .../src/server/api/endpoints/admin/meta.ts    |   2 +-
 .../api/endpoints/auth/session/generate.ts    |   2 +-
 .../src/server/api/endpoints/fetch-rss.ts     |   2 +-
 .../server/api/endpoints/i/2fa/key-done.ts    |   2 +-
 .../server/api/endpoints/i/2fa/register.ts    |   2 +-
 .../src/server/api/endpoints/i/move.ts        |   2 +-
 .../server/api/endpoints/i/update-email.ts    |   2 +-
 .../backend/src/server/api/endpoints/meta.ts  |   2 +-
 .../api/endpoints/request-reset-password.ts   |   2 +-
 .../api/endpoints/username/available.ts       |   2 +-
 packages/backend/src/server/api/index.ts      |   2 +-
 .../src/server/api/mastodon/endpoints/meta.ts |   2 +-
 .../src/server/api/openapi/gen-spec.ts        |   2 +-
 .../backend/src/server/api/private/signin.ts  |   2 +-
 .../backend/src/server/api/private/signup.ts  |   2 +-
 packages/backend/src/server/index.ts          |   2 +-
 packages/backend/src/server/nodeinfo.ts       |   2 +-
 packages/backend/src/server/web/feed.ts       |   2 +-
 packages/backend/src/server/web/index.ts      |   2 +-
 packages/backend/src/server/web/manifest.ts   |   2 +-
 .../backend/src/server/web/url-preview.ts     |   2 +-
 packages/backend/src/server/well-known.ts     |   2 +-
 .../src/services/drive/internal-storage.ts    |   2 +-
 packages/backend/src/services/fetch-rel-me.ts |   2 +-
 .../src/services/following/requests/create.ts |   2 +-
 packages/backend/src/services/i/pin.ts        |   2 +-
 packages/backend/src/services/logger.ts       |   2 +-
 .../backend/src/services/messages/delete.ts   |   2 +-
 packages/backend/src/services/note/create.ts  |   2 +-
 packages/backend/src/services/note/delete.ts  |   2 +-
 .../backend/src/services/push-notification.ts |   2 +-
 packages/backend/src/services/send-email.ts   |   2 +-
 packages/backend/src/services/stream.ts       |   2 +-
 packages/backend/src/services/suspend-user.ts |   2 +-
 .../backend/src/services/unsuspend-user.ts    |   2 +-
 104 files changed, 375 insertions(+), 262 deletions(-)
 create mode 100644 packages/backend/src/config.ts
 delete mode 100644 packages/backend/src/config/index.ts
 delete mode 100644 packages/backend/src/config/load.ts
 delete mode 100644 packages/backend/src/config/types.ts

diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts
index 1cf961bd30..d985eb368d 100644
--- a/packages/backend-rs/index.d.ts
+++ b/packages/backend-rs/index.d.ts
@@ -12,7 +12,7 @@ export interface EnvConfig {
   withLogTime: boolean
   slow: boolean
 }
-export function readEnvironmentConfig(): EnvConfig
+export function loadEnv(): EnvConfig
 export interface ServerConfig {
   url: string
   port: number
@@ -29,7 +29,7 @@ export interface ServerConfig {
   /** `NapiValue` is not implemented for `u64` */
   maxFileSize?: number
   accessLog?: string
-  clusterLimits?: WorkerConfig
+  clusterLimits?: _WorkerConfig
   cuid?: IdConfig
   outgoingAddress?: string
   deliverJobConcurrency?: number
@@ -76,6 +76,10 @@ export interface TlsConfig {
   host: string
   rejectUnauthorized: boolean
 }
+export interface WorkerConfig {
+  web: number
+  queue: number
+}
 export interface WorkerConfig {
   web?: number
   queue?: number
@@ -121,7 +125,67 @@ export interface ObjectStorageConfig {
   setPublicReadOnUpload?: boolean
   s3ForcePathStyle?: boolean
 }
-export function readServerConfig(): ServerConfig
+export interface Config {
+  url: string
+  port: number
+  bind?: string
+  disableHsts?: boolean
+  db: DbConfig
+  redis: RedisConfig
+  cacheServer?: RedisConfig
+  proxy?: string
+  proxySmtp?: string
+  proxyBypassHosts?: Array<string>
+  allowedPrivateNetworks?: Array<string>
+  maxFileSize?: number
+  accessLog?: string
+  clusterLimits: WorkerConfig
+  cuid?: IdConfig
+  outgoingAddress?: string
+  deliverJobConcurrency?: number
+  inboxJobConcurrency?: number
+  deliverJobPerSec?: number
+  inboxJobPerSec?: number
+  deliverJobMaxAttempts?: number
+  inboxJobMaxAttempts?: number
+  logLevel?: Array<string>
+  syslog?: SysLogConfig
+  proxyRemoteFiles?: boolean
+  mediaProxy?: string
+  summalyProxyUrl?: string
+  reservedUsernames?: Array<string>
+  maxUserSignups?: number
+  isManagedHosting?: boolean
+  maxNoteLength?: number
+  maxCaptionLength?: number
+  deepl?: DeepLConfig
+  libreTranslate?: LibreTranslateConfig
+  email?: EmailConfig
+  objectStorage?: ObjectStorageConfig
+  version: string
+  host: string
+  hostname: string
+  scheme: string
+  wsScheme: string
+  apiUrl: string
+  wsUrl: string
+  authUrl: string
+  driveUrl: string
+  userAgent: string
+  clientEntry: Manifest
+}
+export interface Manifest {
+  file: string
+  name: string
+  src: string
+  isEntry: boolean
+  isDynamicEntry: boolean
+  imports: Array<string>
+  dynamicImports: Array<string>
+  css: Array<string>
+  assets: Array<string>
+}
+export function loadConfig(): Config
 export interface Acct {
   username: string
   host: string | null
diff --git a/packages/backend-rs/index.js b/packages/backend-rs/index.js
index 1ea7bb5bed..5fd1e9d784 100644
--- a/packages/backend-rs/index.js
+++ b/packages/backend-rs/index.js
@@ -310,10 +310,10 @@ if (!nativeBinding) {
   throw new Error(`Failed to load native binding`)
 }
 
-const { readEnvironmentConfig, readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getNoteSummary, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
+const { loadEnv, loadConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, getNoteSummary, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
 
-module.exports.readEnvironmentConfig = readEnvironmentConfig
-module.exports.readServerConfig = readServerConfig
+module.exports.loadEnv = loadEnv
+module.exports.loadConfig = loadConfig
 module.exports.stringToAcct = stringToAcct
 module.exports.acctToString = acctToString
 module.exports.checkWordMute = checkWordMute
diff --git a/packages/backend-rs/src/config/environment.rs b/packages/backend-rs/src/config/environment.rs
index 7d66aec7ba..1825af326a 100644
--- a/packages/backend-rs/src/config/environment.rs
+++ b/packages/backend-rs/src/config/environment.rs
@@ -11,7 +11,7 @@ pub struct EnvConfig {
 }
 
 #[crate::export]
-pub fn read_environment_config() -> EnvConfig {
+pub fn load_env() -> EnvConfig {
     let node_env = std::env::var("NODE_ENV").unwrap_or_default().to_lowercase();
     let is_testing = node_env == "test";
 
diff --git a/packages/backend-rs/src/config/server.rs b/packages/backend-rs/src/config/server.rs
index 125bae90b9..4b9fbc7131 100644
--- a/packages/backend-rs/src/config/server.rs
+++ b/packages/backend-rs/src/config/server.rs
@@ -6,7 +6,7 @@ use std::fs;
 #[derive(Clone, Debug, PartialEq, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[crate::export(object, use_nullable = false)]
-pub struct ServerConfig {
+struct ServerConfig {
     pub url: String,
     pub port: u16,
     /// host to listen on
@@ -25,7 +25,7 @@ pub struct ServerConfig {
     /// `NapiValue` is not implemented for `u64`
     pub max_file_size: Option<i64>,
     pub access_log: Option<String>,
-    pub cluster_limits: Option<WorkerConfig>,
+    pub cluster_limits: Option<_WorkerConfig>,
     pub cuid: Option<IdConfig>,
     pub outgoing_address: Option<String>,
 
@@ -94,10 +94,16 @@ pub struct TlsConfig {
     pub reject_unauthorized: bool,
 }
 
+#[crate::export(object, use_nullable = false)]
+pub struct WorkerConfig {
+    pub web: u32,
+    pub queue: u32,
+}
+
 #[derive(Clone, Debug, PartialEq, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[crate::export(object, use_nullable = false)]
-pub struct WorkerConfig {
+pub struct _WorkerConfig {
     pub web: Option<u32>,
     pub queue: Option<u32>,
 }
@@ -167,17 +173,198 @@ pub struct ObjectStorageConfig {
     pub s3_force_path_style: Option<bool>,
 }
 
-#[crate::export]
-pub fn read_server_config() -> ServerConfig {
+#[crate::export(object, use_nullable = false)]
+pub struct Config {
+    // ServerConfig (from default.yml)
+    pub url: String,
+    pub port: u16,
+    pub bind: Option<String>,
+    pub disable_hsts: Option<bool>,
+    pub db: DbConfig,
+    pub redis: RedisConfig,
+    pub cache_server: Option<RedisConfig>,
+    pub proxy: Option<String>,
+    pub proxy_smtp: Option<String>,
+    pub proxy_bypass_hosts: Option<Vec<String>>,
+    pub allowed_private_networks: Option<Vec<String>>,
+    pub max_file_size: Option<i64>,
+    pub access_log: Option<String>,
+    pub cluster_limits: WorkerConfig,
+    pub cuid: Option<IdConfig>,
+    pub outgoing_address: Option<String>,
+    pub deliver_job_concurrency: Option<u32>,
+    pub inbox_job_concurrency: Option<u32>,
+    pub deliver_job_per_sec: Option<u32>,
+    pub inbox_job_per_sec: Option<u32>,
+    pub deliver_job_max_attempts: Option<u32>,
+    pub inbox_job_max_attempts: Option<u32>,
+    pub log_level: Option<Vec<String>>,
+    pub syslog: Option<SysLogConfig>,
+    pub proxy_remote_files: Option<bool>,
+    pub media_proxy: Option<String>,
+    pub summaly_proxy_url: Option<String>,
+    pub reserved_usernames: Option<Vec<String>>,
+    pub max_user_signups: Option<u32>,
+    pub is_managed_hosting: Option<bool>,
+    pub max_note_length: Option<u32>,
+    pub max_caption_length: Option<u32>,
+    pub deepl: Option<DeepLConfig>,
+    pub libre_translate: Option<LibreTranslateConfig>,
+    pub email: Option<EmailConfig>,
+    pub object_storage: Option<ObjectStorageConfig>,
+
+    // Mixin
+    pub version: String,
+    pub host: String,
+    pub hostname: String,
+    pub scheme: String,
+    pub ws_scheme: String,
+    pub api_url: String,
+    pub ws_url: String,
+    pub auth_url: String,
+    pub drive_url: String,
+    pub user_agent: String,
+    pub client_entry: Manifest,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct Meta {
+    pub version: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+struct ManifestJson {
+    #[serde(rename = "src/init.ts")]
+    pub init_ts: Manifest,
+}
+
+#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[crate::export(object, use_nullable = false)]
+pub struct Manifest {
+    pub file: String,
+    pub name: String,
+    pub src: String,
+    pub is_entry: bool,
+    pub is_dynamic_entry: bool,
+    pub imports: Vec<String>,
+    pub dynamic_imports: Vec<String>,
+    pub css: Vec<String>,
+    pub assets: Vec<String>,
+}
+
+fn read_config_file() -> ServerConfig {
     let cwd = env::current_dir().unwrap();
     let yml = fs::File::open(cwd.join("../../.config/default.yml"))
         .expect("Failed to open '.config/default.yml'");
-    let mut data: ServerConfig = serde_yaml::from_reader(yml).expect("Failed to parse yaml");
+    let mut data: ServerConfig =
+        serde_yaml::from_reader(yml).expect("Failed to parse .config/default.yml");
+
     data.url = url::Url::parse(&data.url)
         .expect("Config url is invalid")
         .origin()
         .ascii_serialization();
+
+    if data.bind.is_none() {
+        data.bind = std::env::var("BIND").ok()
+    }
+
     data
 }
 
-pub static SERVER_CONFIG: Lazy<ServerConfig> = Lazy::new(read_server_config);
+fn read_meta() -> Meta {
+    let cwd = env::current_dir().unwrap();
+    let meta_json = fs::File::open(cwd.join("../../built/meta.json"))
+        .expect("Failed to open 'built/meta.json'");
+    serde_json::from_reader(meta_json).expect("Failed to parse built/meta.json")
+}
+
+fn read_manifest() -> Manifest {
+    let cwd = env::current_dir().unwrap();
+    let manifest_json = fs::File::open(cwd.join("../../built/_client_dist_/manifest.json"))
+        .expect("Failed to open 'built/_client_dist_/manifest.json'");
+    let manifest: ManifestJson = serde_json::from_reader(manifest_json)
+        .expect("Failed to parse built/_client_dist_/manifest.json");
+
+    manifest.init_ts
+}
+
+#[crate::export]
+fn load_config() -> Config {
+    let server_config = read_config_file();
+    let version = read_meta().version;
+    let manifest = read_manifest();
+    let url = url::Url::parse(&server_config.url).expect("Config url is invalid");
+    let host = url
+        .host_str()
+        .expect("Hostname is missing in the config url")
+        .to_owned();
+    let hostname = url
+        .domain()
+        .expect("Domain is missing in the config url")
+        .to_owned();
+    let scheme = url.scheme().to_owned();
+    let ws_scheme = scheme.replace("http", "ws");
+
+    let cluster_limits = match server_config.cluster_limits {
+        Some(cl) => WorkerConfig {
+            web: cl.web.unwrap_or(1),
+            queue: cl.queue.unwrap_or(1),
+        },
+        None => WorkerConfig { web: 1, queue: 1 },
+    };
+
+    Config {
+        url: server_config.url,
+        port: server_config.port,
+        bind: server_config.bind,
+        disable_hsts: server_config.disable_hsts,
+        db: server_config.db,
+        redis: server_config.redis,
+        cache_server: server_config.cache_server,
+        proxy: server_config.proxy,
+        proxy_smtp: server_config.proxy_smtp,
+        proxy_bypass_hosts: server_config.proxy_bypass_hosts,
+        allowed_private_networks: server_config.allowed_private_networks,
+        max_file_size: server_config.max_file_size,
+        access_log: server_config.access_log,
+        cluster_limits,
+        cuid: server_config.cuid,
+        outgoing_address: server_config.outgoing_address,
+        deliver_job_concurrency: server_config.deliver_job_concurrency,
+        inbox_job_concurrency: server_config.inbox_job_concurrency,
+        deliver_job_per_sec: server_config.deliver_job_per_sec,
+        inbox_job_per_sec: server_config.inbox_job_per_sec,
+        deliver_job_max_attempts: server_config.deliver_job_max_attempts,
+        inbox_job_max_attempts: server_config.inbox_job_max_attempts,
+        log_level: server_config.log_level,
+        syslog: server_config.syslog,
+        proxy_remote_files: server_config.proxy_remote_files,
+        media_proxy: server_config.media_proxy,
+        summaly_proxy_url: server_config.summaly_proxy_url,
+        reserved_usernames: server_config.reserved_usernames,
+        max_user_signups: server_config.max_user_signups,
+        is_managed_hosting: server_config.is_managed_hosting,
+        max_note_length: server_config.max_note_length,
+        max_caption_length: server_config.max_caption_length,
+        deepl: server_config.deepl,
+        libre_translate: server_config.libre_translate,
+        email: server_config.email,
+        object_storage: server_config.object_storage,
+
+        ws_url: format!("{}://{}", ws_scheme, host),
+        api_url: format!("{}://{}/api", scheme, host),
+        auth_url: format!("{}://{}/auth", scheme, host),
+        drive_url: format!("{}://{}/files", scheme, host),
+        user_agent: format!("Firefish/{} ({})", version, url),
+        version,
+        host,
+        hostname,
+        scheme,
+        ws_scheme,
+        client_entry: manifest,
+    }
+}
+
+pub static CONFIG: Lazy<Config> = Lazy::new(load_config);
diff --git a/packages/backend-rs/src/database/mod.rs b/packages/backend-rs/src/database/mod.rs
index f598e35cc7..a60d20af9c 100644
--- a/packages/backend-rs/src/database/mod.rs
+++ b/packages/backend-rs/src/database/mod.rs
@@ -1,4 +1,4 @@
-use crate::config::server::SERVER_CONFIG;
+use crate::config::server::CONFIG;
 use sea_orm::{Database, DbConn, DbErr};
 
 static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::new();
@@ -6,11 +6,11 @@ static DB_CONN: once_cell::sync::OnceCell<DbConn> = once_cell::sync::OnceCell::n
 async fn init_database() -> Result<&'static DbConn, DbErr> {
     let database_uri = format!(
         "postgres://{}:{}@{}:{}/{}",
-        SERVER_CONFIG.db.user,
-        urlencoding::encode(&SERVER_CONFIG.db.pass),
-        SERVER_CONFIG.db.host,
-        SERVER_CONFIG.db.port,
-        SERVER_CONFIG.db.db,
+        CONFIG.db.user,
+        urlencoding::encode(&CONFIG.db.pass),
+        CONFIG.db.host,
+        CONFIG.db.port,
+        CONFIG.db.db,
     );
     let conn = Database::connect(database_uri).await?;
     Ok(DB_CONN.get_or_init(move || conn))
diff --git a/packages/backend-rs/src/misc/convert_host.rs b/packages/backend-rs/src/misc/convert_host.rs
index 34a0792c62..cff52aeb07 100644
--- a/packages/backend-rs/src/misc/convert_host.rs
+++ b/packages/backend-rs/src/misc/convert_host.rs
@@ -1,4 +1,4 @@
-use crate::config::server::SERVER_CONFIG;
+use crate::config::server::CONFIG;
 
 #[derive(thiserror::Error, Debug)]
 pub enum Error {
@@ -14,21 +14,21 @@ pub enum Error {
 pub fn get_full_ap_account(username: &str, host: Option<&str>) -> Result<String, Error> {
     Ok(match host {
         Some(host) => format!("{}@{}", username, to_puny(host)?),
-        None => format!("{}@{}", username, extract_host(&SERVER_CONFIG.url)?),
+        None => format!("{}@{}", username, extract_host(&CONFIG.url)?),
     })
 }
 
 #[crate::export]
 pub fn is_self_host(host: Option<&str>) -> Result<bool, Error> {
     Ok(match host {
-        Some(host) => extract_host(&SERVER_CONFIG.url)? == to_puny(host)?,
+        Some(host) => extract_host(&CONFIG.url)? == to_puny(host)?,
         None => true,
     })
 }
 
 #[crate::export]
 pub fn is_same_origin(uri: &str) -> Result<bool, Error> {
-    Ok(url::Url::parse(uri)?.origin().ascii_serialization() == SERVER_CONFIG.url)
+    Ok(url::Url::parse(uri)?.origin().ascii_serialization() == CONFIG.url)
 }
 
 #[crate::export]
diff --git a/packages/backend/src/boot/index.ts b/packages/backend/src/boot/index.ts
index 9854d2dce4..3e542a6e36 100644
--- a/packages/backend/src/boot/index.ts
+++ b/packages/backend/src/boot/index.ts
@@ -3,7 +3,7 @@ import chalk from "chalk";
 import Xev from "xev";
 
 import Logger from "@/services/logger.js";
-import { envOption } from "@/config/index.js";
+import { envOption } from "@/config.js";
 import { inspect } from "node:util";
 
 // for typeorm
diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts
index 3ba2d0cf50..44c4a8a2f1 100644
--- a/packages/backend/src/boot/master.ts
+++ b/packages/backend/src/boot/master.ts
@@ -8,9 +8,8 @@ import chalkTemplate from "chalk-template";
 import semver from "semver";
 
 import Logger from "@/services/logger.js";
-import loadConfig from "@/config/load.js";
-import type { Config } from "@/config/types.js";
-import { envOption } from "@/config/index.js";
+import type { Config } from "backend-rs";
+import { config, envOption } from "@/config.js";
 import { showMachineInfo } from "@/misc/show-machine-info.js";
 import { db, initDb } from "@/db/postgre.js";
 import { inspect } from "node:util";
@@ -87,15 +86,12 @@ function greet() {
  * Init master process
  */
 export async function masterMain() {
-	let config!: Config;
-
 	// initialize app
 	try {
 		greet();
 		showEnvironment();
 		await showMachineInfo(bootLogger);
 		showNodejsVersion();
-		config = loadConfigBoot();
 		await connectDb();
 	} catch (e) {
 		bootLogger.error(
@@ -154,28 +150,6 @@ function showNodejsVersion(): void {
 	}
 }
 
-function loadConfigBoot(): Config {
-	const configLogger = bootLogger.createSubLogger("config");
-	let config;
-
-	try {
-		config = loadConfig();
-	} catch (exception) {
-		if (exception.code === "ENOENT") {
-			configLogger.error("Configuration file not found", null, true);
-			process.exit(1);
-		} else if (e instanceof Error) {
-			configLogger.error(e.message);
-			process.exit(1);
-		}
-		throw exception;
-	}
-
-	configLogger.succ("Loaded");
-
-	return config;
-}
-
 async function connectDb(): Promise<void> {
 	const dbLogger = bootLogger.createSubLogger("db");
 
diff --git a/packages/backend/src/boot/worker.ts b/packages/backend/src/boot/worker.ts
index 647ea40fbd..cae861230f 100644
--- a/packages/backend/src/boot/worker.ts
+++ b/packages/backend/src/boot/worker.ts
@@ -1,5 +1,5 @@
 import cluster from "node:cluster";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { initDb } from "@/db/postgre.js";
 import { initIdGenerator } from "backend-rs";
 import os from "node:os";
diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts
new file mode 100644
index 0000000000..c91294b611
--- /dev/null
+++ b/packages/backend/src/config.ts
@@ -0,0 +1,4 @@
+import { loadConfig, loadEnv } from "backend-rs";
+
+export const config = loadConfig();
+export const envOption = loadEnv();
diff --git a/packages/backend/src/config/index.ts b/packages/backend/src/config/index.ts
deleted file mode 100644
index fe87e5026a..0000000000
--- a/packages/backend/src/config/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import load from "./load.js";
-import { readEnvironmentConfig } from "backend-rs";
-
-export default load();
-export const envOption = readEnvironmentConfig();
diff --git a/packages/backend/src/config/load.ts b/packages/backend/src/config/load.ts
deleted file mode 100644
index 682bf309d2..0000000000
--- a/packages/backend/src/config/load.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * Config loader
- */
-
-import * as fs from "node:fs";
-import { fileURLToPath } from "node:url";
-import { dirname } from "node:path";
-import type { Mixin } from "./types.js";
-import { readServerConfig } from "backend-rs";
-
-const _filename = fileURLToPath(import.meta.url);
-const _dirname = dirname(_filename);
-
-/**
- * Path of configuration directory
- */
-const dir = `${_dirname}/../../../../.config`;
-
-/**
- * Path of configuration file
- */
-const path =
-	process.env.NODE_ENV === "test" ? `${dir}/test.yml` : `${dir}/default.yml`;
-
-export default function load() {
-	const meta = JSON.parse(
-		fs.readFileSync(`${_dirname}/../../../../built/meta.json`, "utf-8"),
-	);
-	const clientManifest = JSON.parse(
-		fs.readFileSync(
-			`${_dirname}/../../../../built/_client_dist_/manifest.json`,
-			"utf-8",
-		),
-	);
-	const config = readServerConfig();
-
-	const mixin = {} as Mixin;
-
-	const url = tryCreateUrl(config.url);
-
-	config.url = url.origin;
-
-	config.port = config.port || parseInt(process.env.PORT || "", 10);
-	config.bind = config.bind || process.env.BIND;
-
-	mixin.version = meta.version;
-	mixin.host = url.host;
-	mixin.hostname = url.hostname;
-	mixin.scheme = url.protocol.replace(/:$/, "");
-	mixin.wsScheme = mixin.scheme.replace("http", "ws");
-	mixin.wsUrl = `${mixin.wsScheme}://${mixin.host}`;
-	mixin.apiUrl = `${mixin.scheme}://${mixin.host}/api`;
-	mixin.authUrl = `${mixin.scheme}://${mixin.host}/auth`;
-	mixin.driveUrl = `${mixin.scheme}://${mixin.host}/files`;
-	mixin.userAgent = `Firefish/${meta.version} (${config.url})`;
-	mixin.clientEntry = clientManifest["src/init.ts"];
-
-	if (config.proxyRemoteFiles == null) config.proxyRemoteFiles = true;
-	if (!config.redis.prefix) config.redis.prefix = mixin.hostname;
-	if (config.cacheServer && !config.cacheServer.prefix)
-		config.cacheServer.prefix = mixin.hostname;
-
-	if (!config.clusterLimits) {
-		config.clusterLimits = {
-			web: 1,
-			queue: 1,
-		};
-	} else {
-		config.clusterLimits = {
-			web: 1,
-			queue: 1,
-			...config.clusterLimits,
-		};
-
-		if (config.clusterLimits.web! < 1 || config.clusterLimits.queue! < 1) {
-			throw new Error("Invalid cluster limits");
-		}
-	}
-
-	return Object.assign(config, mixin);
-}
-
-function tryCreateUrl(url: string) {
-	try {
-		return new URL(url);
-	} catch (e) {
-		throw new Error(`url="${url}" is not a valid URL.`);
-	}
-}
diff --git a/packages/backend/src/config/types.ts b/packages/backend/src/config/types.ts
deleted file mode 100644
index 6b593d3b2d..0000000000
--- a/packages/backend/src/config/types.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import type { ServerConfig } from "backend-rs";
-
-/**
- * Firefish が自動的に(ユーザーが設定した情報から推論して)設定する情報
- */
-export type Mixin = {
-	version: string;
-	host: string;
-	hostname: string;
-	scheme: string;
-	wsScheme: string;
-	apiUrl: string;
-	wsUrl: string;
-	authUrl: string;
-	driveUrl: string;
-	userAgent: string;
-	clientEntry: string;
-};
-
-export type Config = ServerConfig & Mixin;
diff --git a/packages/backend/src/const.ts b/packages/backend/src/const.ts
index 39ff99fda7..2c52e2b009 100644
--- a/packages/backend/src/const.ts
+++ b/packages/backend/src/const.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import {
 	DB_MAX_IMAGE_COMMENT_LENGTH,
 	DB_MAX_NOTE_TEXT_LENGTH,
diff --git a/packages/backend/src/db/postgre.ts b/packages/backend/src/db/postgre.ts
index 6baccaa271..e0ab9d6d37 100644
--- a/packages/backend/src/db/postgre.ts
+++ b/packages/backend/src/db/postgre.ts
@@ -5,7 +5,7 @@ pg.types.setTypeParser(20, Number);
 import type { Logger } from "typeorm";
 import { DataSource } from "typeorm";
 import * as highlight from "cli-highlight";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 import { User } from "@/models/entities/user.js";
 import { DriveFile } from "@/models/entities/drive-file.js";
diff --git a/packages/backend/src/db/redis.ts b/packages/backend/src/db/redis.ts
index 215effd8ea..dc703e9d47 100644
--- a/packages/backend/src/db/redis.ts
+++ b/packages/backend/src/db/redis.ts
@@ -1,5 +1,5 @@
 import Redis from "ioredis";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 export function createConnection() {
 	let source = config.redis;
diff --git a/packages/backend/src/mfm/to-html.ts b/packages/backend/src/mfm/to-html.ts
index 7b7c0967a1..64aa9d7164 100644
--- a/packages/backend/src/mfm/to-html.ts
+++ b/packages/backend/src/mfm/to-html.ts
@@ -1,7 +1,7 @@
 import { type HTMLElement, Window } from "happy-dom";
 import type * as mfm from "mfm-js";
 import katex from "katex";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { intersperse } from "@/prelude/array.js";
 import type { IMentionedRemoteUsers } from "@/models/entities/note.js";
 
diff --git a/packages/backend/src/misc/captcha.ts b/packages/backend/src/misc/captcha.ts
index c163d4d82d..d0969b0205 100644
--- a/packages/backend/src/misc/captcha.ts
+++ b/packages/backend/src/misc/captcha.ts
@@ -1,7 +1,7 @@
 import fetch from "node-fetch";
 import { URLSearchParams } from "node:url";
 import { getAgentByUrl } from "@/misc/fetch.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { inspect } from "node:util";
 
 export async function verifyRecaptcha(secret: string, response: string) {
diff --git a/packages/backend/src/misc/download-url.ts b/packages/backend/src/misc/download-url.ts
index ab04e8aa9c..1bfd0a9f80 100644
--- a/packages/backend/src/misc/download-url.ts
+++ b/packages/backend/src/misc/download-url.ts
@@ -3,7 +3,7 @@ import * as stream from "node:stream";
 import * as util from "node:util";
 import got, * as Got from "got";
 import { httpAgent, httpsAgent, StatusError } from "./fetch.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import chalk from "chalk";
 import Logger from "@/services/logger.js";
 import IPCIDR from "ip-cidr";
diff --git a/packages/backend/src/misc/fetch.ts b/packages/backend/src/misc/fetch.ts
index 4b8fc048e2..b26fa83052 100644
--- a/packages/backend/src/misc/fetch.ts
+++ b/packages/backend/src/misc/fetch.ts
@@ -4,7 +4,7 @@ import type { URL } from "node:url";
 import CacheableLookup from "cacheable-lookup";
 import fetch, { type RequestRedirect } from "node-fetch";
 import { HttpProxyAgent, HttpsProxyAgent } from "hpagent";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { isValidUrl } from "./is-valid-url.js";
 
 export async function getJson(
diff --git a/packages/backend/src/misc/populate-emojis.ts b/packages/backend/src/misc/populate-emojis.ts
index 4ca60b222f..f2656ea28a 100644
--- a/packages/backend/src/misc/populate-emojis.ts
+++ b/packages/backend/src/misc/populate-emojis.ts
@@ -4,7 +4,7 @@ import type { Emoji } from "@/models/entities/emoji.js";
 import type { Note } from "@/models/entities/note.js";
 import { Cache } from "./cache.js";
 import { decodeReaction, isSelfHost, toPuny } from "backend-rs";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { query } from "@/prelude/url.js";
 import { redisClient } from "@/db/redis.js";
 import type { NoteEdit } from "@/models/entities/note-edit.js";
diff --git a/packages/backend/src/models/repositories/drive-file.ts b/packages/backend/src/models/repositories/drive-file.ts
index 2321f20d4c..757bd77ad6 100644
--- a/packages/backend/src/models/repositories/drive-file.ts
+++ b/packages/backend/src/models/repositories/drive-file.ts
@@ -4,7 +4,7 @@ import type { User } from "@/models/entities/user.js";
 import { toPuny } from "backend-rs";
 import { awaitAll } from "@/prelude/await-all.js";
 import type { Packed } from "@/misc/schema.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { query, appendQuery } from "@/prelude/url.js";
 import { Users, DriveFolders } from "../index.js";
 import { deepClone } from "@/misc/clone.js";
diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts
index 3bc943965b..040106b410 100644
--- a/packages/backend/src/models/repositories/user.ts
+++ b/packages/backend/src/models/repositories/user.ts
@@ -2,7 +2,7 @@ import { In, Not } from "typeorm";
 import Ajv from "ajv";
 import type { ILocalUser, IRemoteUser } from "@/models/entities/user.js";
 import { User } from "@/models/entities/user.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { Packed } from "@/misc/schema.js";
 import type { Promiseable } from "@/prelude/await-all.js";
 import { awaitAll } from "@/prelude/await-all.js";
diff --git a/packages/backend/src/models/schema/federation-instance.ts b/packages/backend/src/models/schema/federation-instance.ts
index 7a8af7f51d..338e079e28 100644
--- a/packages/backend/src/models/schema/federation-instance.ts
+++ b/packages/backend/src/models/schema/federation-instance.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 export const packedFederationInstanceSchema = {
 	type: "object",
diff --git a/packages/backend/src/queue/index.ts b/packages/backend/src/queue/index.ts
index e4e413be52..6272a5e668 100644
--- a/packages/backend/src/queue/index.ts
+++ b/packages/backend/src/queue/index.ts
@@ -1,11 +1,10 @@
 import type httpSignature from "@peertube/http-signature";
 import { v4 as uuid } from "uuid";
 
-import config from "@/config/index.js";
+import { config, envOption } from "@/config.js";
 import type { DriveFile } from "@/models/entities/drive-file.js";
 import type { IActivity } from "@/remote/activitypub/type.js";
 import type { Webhook, webhookEventTypes } from "@/models/entities/webhook.js";
-import { envOption } from "@/config/index.js";
 
 import processDeliver from "./processors/deliver.js";
 import processInbox from "./processors/inbox.js";
@@ -24,10 +23,9 @@ import {
 	objectStorageQueue,
 	endedPollNotificationQueue,
 	webhookDeliverQueue,
-	backgroundQueue,
 } from "./queues.js";
 import type { ThinUser } from "./types.js";
-import { Note } from "@/models/entities/note.js";
+import type { Note } from "@/models/entities/note.js";
 
 function renderError(e: Error): any {
 	return {
diff --git a/packages/backend/src/queue/initialize.ts b/packages/backend/src/queue/initialize.ts
index 0f9c83132f..3291d47675 100644
--- a/packages/backend/src/queue/initialize.ts
+++ b/packages/backend/src/queue/initialize.ts
@@ -1,5 +1,5 @@
 import Bull from "bull";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 export function initialize<T>(name: string, limitPerSec = -1) {
 	return new Bull<T>(name, {
diff --git a/packages/backend/src/queue/processors/db/export-custom-emojis.ts b/packages/backend/src/queue/processors/db/export-custom-emojis.ts
index a1ca3a91c5..157751c1aa 100644
--- a/packages/backend/src/queue/processors/db/export-custom-emojis.ts
+++ b/packages/backend/src/queue/processors/db/export-custom-emojis.ts
@@ -9,7 +9,7 @@ import { format as dateFormat } from "date-fns";
 import { Users, Emojis } from "@/models/index.js";
 import { createTemp, createTempDir } from "@/misc/create-temp.js";
 import { downloadUrl } from "@/misc/download-url.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { IsNull } from "typeorm";
 import { inspect } from "node:util";
 
diff --git a/packages/backend/src/queue/processors/webhook-deliver.ts b/packages/backend/src/queue/processors/webhook-deliver.ts
index 12c9a05498..63a16c373b 100644
--- a/packages/backend/src/queue/processors/webhook-deliver.ts
+++ b/packages/backend/src/queue/processors/webhook-deliver.ts
@@ -3,7 +3,7 @@ import Logger from "@/services/logger.js";
 import type { WebhookDeliverJobData } from "../types.js";
 import { getResponse, StatusError } from "@/misc/fetch.js";
 import { Webhooks } from "@/models/index.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 const logger = new Logger("webhook");
 
diff --git a/packages/backend/src/queue/queues.ts b/packages/backend/src/queue/queues.ts
index 6b0eb2de42..06b9567e74 100644
--- a/packages/backend/src/queue/queues.ts
+++ b/packages/backend/src/queue/queues.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { initialize as initializeQueue } from "./initialize.js";
 import type {
 	DeliverJobData,
diff --git a/packages/backend/src/remote/activitypub/check-fetch.ts b/packages/backend/src/remote/activitypub/check-fetch.ts
index 12ea63a931..04d989064f 100644
--- a/packages/backend/src/remote/activitypub/check-fetch.ts
+++ b/packages/backend/src/remote/activitypub/check-fetch.ts
@@ -1,6 +1,6 @@
 import { URL } from "url";
 import httpSignature, { IParsedSignature } from "@peertube/http-signature";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { fetchMeta } from "backend-rs";
 import { toPuny } from "backend-rs";
 import DbResolver from "@/remote/activitypub/db-resolver.js";
diff --git a/packages/backend/src/remote/activitypub/db-resolver.ts b/packages/backend/src/remote/activitypub/db-resolver.ts
index a753606a14..088a2db9da 100644
--- a/packages/backend/src/remote/activitypub/db-resolver.ts
+++ b/packages/backend/src/remote/activitypub/db-resolver.ts
@@ -1,5 +1,5 @@
 import escapeRegexp from "escape-regexp";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { Note } from "@/models/entities/note.js";
 import type {
 	CacheableRemoteUser,
diff --git a/packages/backend/src/remote/activitypub/kernel/flag/index.ts b/packages/backend/src/remote/activitypub/kernel/flag/index.ts
index 0f83f6b449..c556605865 100644
--- a/packages/backend/src/remote/activitypub/kernel/flag/index.ts
+++ b/packages/backend/src/remote/activitypub/kernel/flag/index.ts
@@ -1,5 +1,5 @@
 import type { CacheableRemoteUser } from "@/models/entities/user.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { IFlag } from "../../type.js";
 import { getApIds } from "../../type.js";
 import { AbuseUserReports, Users } from "@/models/index.js";
diff --git a/packages/backend/src/remote/activitypub/renderer/accept.ts b/packages/backend/src/remote/activitypub/renderer/accept.ts
index fd145dcf97..2d27a1b29d 100644
--- a/packages/backend/src/remote/activitypub/renderer/accept.ts
+++ b/packages/backend/src/remote/activitypub/renderer/accept.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 
 export default (object: any, user: { id: User["id"]; host: null }) => ({
diff --git a/packages/backend/src/remote/activitypub/renderer/add.ts b/packages/backend/src/remote/activitypub/renderer/add.ts
index d8203ac1ea..14c71694e1 100644
--- a/packages/backend/src/remote/activitypub/renderer/add.ts
+++ b/packages/backend/src/remote/activitypub/renderer/add.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { ILocalUser } from "@/models/entities/user.js";
 
 export default (user: ILocalUser, target: any, object: any) => ({
diff --git a/packages/backend/src/remote/activitypub/renderer/announce.ts b/packages/backend/src/remote/activitypub/renderer/announce.ts
index 1fd1842acf..0cc9bec6f4 100644
--- a/packages/backend/src/remote/activitypub/renderer/announce.ts
+++ b/packages/backend/src/remote/activitypub/renderer/announce.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { Note } from "@/models/entities/note.js";
 
 export default (object: any, note: Note) => {
diff --git a/packages/backend/src/remote/activitypub/renderer/block.ts b/packages/backend/src/remote/activitypub/renderer/block.ts
index c2ea267f38..5169e0d550 100644
--- a/packages/backend/src/remote/activitypub/renderer/block.ts
+++ b/packages/backend/src/remote/activitypub/renderer/block.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { Blocking } from "@/models/entities/blocking.js";
 
 /**
diff --git a/packages/backend/src/remote/activitypub/renderer/create.ts b/packages/backend/src/remote/activitypub/renderer/create.ts
index 857f5722cc..89b14b88b2 100644
--- a/packages/backend/src/remote/activitypub/renderer/create.ts
+++ b/packages/backend/src/remote/activitypub/renderer/create.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { Note } from "@/models/entities/note.js";
 
 export default (object: any, note: Note) => {
diff --git a/packages/backend/src/remote/activitypub/renderer/delete.ts b/packages/backend/src/remote/activitypub/renderer/delete.ts
index 70bdc34922..0d2105941e 100644
--- a/packages/backend/src/remote/activitypub/renderer/delete.ts
+++ b/packages/backend/src/remote/activitypub/renderer/delete.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 
 export default (object: any, user: { id: User["id"]; host: null }) => ({
diff --git a/packages/backend/src/remote/activitypub/renderer/emoji.ts b/packages/backend/src/remote/activitypub/renderer/emoji.ts
index 3d9b8cd55b..dab0e8cac7 100644
--- a/packages/backend/src/remote/activitypub/renderer/emoji.ts
+++ b/packages/backend/src/remote/activitypub/renderer/emoji.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { Emoji } from "@/models/entities/emoji.js";
 
 export default (emoji: Emoji) => ({
diff --git a/packages/backend/src/remote/activitypub/renderer/flag.ts b/packages/backend/src/remote/activitypub/renderer/flag.ts
index 44da33f5c2..1fa260be5e 100644
--- a/packages/backend/src/remote/activitypub/renderer/flag.ts
+++ b/packages/backend/src/remote/activitypub/renderer/flag.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { ILocalUser } from "@/models/entities/user.js";
 
 // to anonymise reporters, the reporting actor must be a system user
diff --git a/packages/backend/src/remote/activitypub/renderer/follow-relay.ts b/packages/backend/src/remote/activitypub/renderer/follow-relay.ts
index ad7f05bf84..b62d9c4011 100644
--- a/packages/backend/src/remote/activitypub/renderer/follow-relay.ts
+++ b/packages/backend/src/remote/activitypub/renderer/follow-relay.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { Relay } from "@/models/entities/relay.js";
 import type { ILocalUser } from "@/models/entities/user.js";
 
diff --git a/packages/backend/src/remote/activitypub/renderer/follow-user.ts b/packages/backend/src/remote/activitypub/renderer/follow-user.ts
index 22ee429ff6..93228a6327 100644
--- a/packages/backend/src/remote/activitypub/renderer/follow-user.ts
+++ b/packages/backend/src/remote/activitypub/renderer/follow-user.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { Users } from "@/models/index.js";
 import type { User } from "@/models/entities/user.js";
 
diff --git a/packages/backend/src/remote/activitypub/renderer/follow.ts b/packages/backend/src/remote/activitypub/renderer/follow.ts
index 3ff89c12aa..30ad799507 100644
--- a/packages/backend/src/remote/activitypub/renderer/follow.ts
+++ b/packages/backend/src/remote/activitypub/renderer/follow.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 import { Users } from "@/models/index.js";
 
diff --git a/packages/backend/src/remote/activitypub/renderer/hashtag.ts b/packages/backend/src/remote/activitypub/renderer/hashtag.ts
index a00cd1ff5e..ab6651f55d 100644
--- a/packages/backend/src/remote/activitypub/renderer/hashtag.ts
+++ b/packages/backend/src/remote/activitypub/renderer/hashtag.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 export default (tag: string) => ({
 	type: "Hashtag",
diff --git a/packages/backend/src/remote/activitypub/renderer/index.ts b/packages/backend/src/remote/activitypub/renderer/index.ts
index 2b6229b3e4..a085443d23 100644
--- a/packages/backend/src/remote/activitypub/renderer/index.ts
+++ b/packages/backend/src/remote/activitypub/renderer/index.ts
@@ -1,5 +1,5 @@
 import { v4 as uuid } from "uuid";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { getUserKeypair } from "@/misc/keypair-store.js";
 import type { User } from "@/models/entities/user.js";
 import { LdSignature } from "../misc/ld-signature.js";
diff --git a/packages/backend/src/remote/activitypub/renderer/key.ts b/packages/backend/src/remote/activitypub/renderer/key.ts
index 084bb5361a..1e01640e59 100644
--- a/packages/backend/src/remote/activitypub/renderer/key.ts
+++ b/packages/backend/src/remote/activitypub/renderer/key.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { ILocalUser } from "@/models/entities/user.js";
 import type { UserKeypair } from "@/models/entities/user-keypair.js";
 import { createPublicKey } from "node:crypto";
diff --git a/packages/backend/src/remote/activitypub/renderer/like.ts b/packages/backend/src/remote/activitypub/renderer/like.ts
index 6f810cd201..ea0df3e359 100644
--- a/packages/backend/src/remote/activitypub/renderer/like.ts
+++ b/packages/backend/src/remote/activitypub/renderer/like.ts
@@ -1,5 +1,5 @@
 import { IsNull } from "typeorm";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { NoteReaction } from "@/models/entities/note-reaction.js";
 import type { Note } from "@/models/entities/note.js";
 import { Emojis } from "@/models/index.js";
diff --git a/packages/backend/src/remote/activitypub/renderer/mention.ts b/packages/backend/src/remote/activitypub/renderer/mention.ts
index e7f0435c16..c935c7d325 100644
--- a/packages/backend/src/remote/activitypub/renderer/mention.ts
+++ b/packages/backend/src/remote/activitypub/renderer/mention.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User, ILocalUser } from "@/models/entities/user.js";
 import { Users } from "@/models/index.js";
 
diff --git a/packages/backend/src/remote/activitypub/renderer/note.ts b/packages/backend/src/remote/activitypub/renderer/note.ts
index f1344c1b03..dc978f1e0e 100644
--- a/packages/backend/src/remote/activitypub/renderer/note.ts
+++ b/packages/backend/src/remote/activitypub/renderer/note.ts
@@ -1,5 +1,5 @@
 import { In, IsNull } from "typeorm";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { Note, IMentionedRemoteUsers } from "@/models/entities/note.js";
 import type { DriveFile } from "@/models/entities/drive-file.js";
 import { DriveFiles, Notes, Users, Emojis, Polls } from "@/models/index.js";
diff --git a/packages/backend/src/remote/activitypub/renderer/person.ts b/packages/backend/src/remote/activitypub/renderer/person.ts
index bba963d72e..c6371440b4 100644
--- a/packages/backend/src/remote/activitypub/renderer/person.ts
+++ b/packages/backend/src/remote/activitypub/renderer/person.ts
@@ -1,6 +1,6 @@
 import { URL } from "node:url";
 import * as mfm from "mfm-js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { ILocalUser } from "@/models/entities/user.js";
 import { DriveFiles, UserProfiles } from "@/models/index.js";
 import { getUserKeypair } from "@/misc/keypair-store.js";
diff --git a/packages/backend/src/remote/activitypub/renderer/question.ts b/packages/backend/src/remote/activitypub/renderer/question.ts
index cb89aa7583..ac62734395 100644
--- a/packages/backend/src/remote/activitypub/renderer/question.ts
+++ b/packages/backend/src/remote/activitypub/renderer/question.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 import type { Note } from "@/models/entities/note.js";
 import type { Poll } from "@/models/entities/poll.js";
diff --git a/packages/backend/src/remote/activitypub/renderer/read.ts b/packages/backend/src/remote/activitypub/renderer/read.ts
index 212e7e8ddf..9ea15b10f7 100644
--- a/packages/backend/src/remote/activitypub/renderer/read.ts
+++ b/packages/backend/src/remote/activitypub/renderer/read.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 import type { MessagingMessage } from "@/models/entities/messaging-message.js";
 
diff --git a/packages/backend/src/remote/activitypub/renderer/reject.ts b/packages/backend/src/remote/activitypub/renderer/reject.ts
index 7ac4452411..75c3b9d065 100644
--- a/packages/backend/src/remote/activitypub/renderer/reject.ts
+++ b/packages/backend/src/remote/activitypub/renderer/reject.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 
 export default (object: any, user: { id: User["id"] }) => ({
diff --git a/packages/backend/src/remote/activitypub/renderer/remove.ts b/packages/backend/src/remote/activitypub/renderer/remove.ts
index e3b3fef856..270744dd30 100644
--- a/packages/backend/src/remote/activitypub/renderer/remove.ts
+++ b/packages/backend/src/remote/activitypub/renderer/remove.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 
 export default (user: { id: User["id"] }, target: any, object: any) => ({
diff --git a/packages/backend/src/remote/activitypub/renderer/undo.ts b/packages/backend/src/remote/activitypub/renderer/undo.ts
index 4394c4bf2f..a0285ea9c7 100644
--- a/packages/backend/src/remote/activitypub/renderer/undo.ts
+++ b/packages/backend/src/remote/activitypub/renderer/undo.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 
 export default (object: any, user: { id: User["id"] }) => {
diff --git a/packages/backend/src/remote/activitypub/renderer/update.ts b/packages/backend/src/remote/activitypub/renderer/update.ts
index ecb0ed2192..b47f7c5cda 100644
--- a/packages/backend/src/remote/activitypub/renderer/update.ts
+++ b/packages/backend/src/remote/activitypub/renderer/update.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 
 export default (object: any, user: { id: User["id"] }) => {
diff --git a/packages/backend/src/remote/activitypub/renderer/vote.ts b/packages/backend/src/remote/activitypub/renderer/vote.ts
index 21234a112d..118e6761ab 100644
--- a/packages/backend/src/remote/activitypub/renderer/vote.ts
+++ b/packages/backend/src/remote/activitypub/renderer/vote.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { Note } from "@/models/entities/note.js";
 import type { IRemoteUser, User } from "@/models/entities/user.js";
 import type { PollVote } from "@/models/entities/poll-vote.js";
diff --git a/packages/backend/src/remote/activitypub/request.ts b/packages/backend/src/remote/activitypub/request.ts
index f6d33b8549..8e3bc764d3 100644
--- a/packages/backend/src/remote/activitypub/request.ts
+++ b/packages/backend/src/remote/activitypub/request.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { getUserKeypair } from "@/misc/keypair-store.js";
 import type { User, ILocalUser } from "@/models/entities/user.js";
 import { StatusError, getResponse } from "@/misc/fetch.js";
diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts
index 79b7962b72..65e6f1d635 100644
--- a/packages/backend/src/remote/activitypub/resolver.ts
+++ b/packages/backend/src/remote/activitypub/resolver.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { ILocalUser } from "@/models/entities/user.js";
 import { getInstanceActor } from "@/services/instance-actor.js";
 import { fetchMeta } from "backend-rs";
diff --git a/packages/backend/src/remote/resolve-user.ts b/packages/backend/src/remote/resolve-user.ts
index 0883386371..69a99c767a 100644
--- a/packages/backend/src/remote/resolve-user.ts
+++ b/packages/backend/src/remote/resolve-user.ts
@@ -1,7 +1,7 @@
 import { URL } from "node:url";
 import chalk from "chalk";
 import { IsNull } from "typeorm";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User, IRemoteUser } from "@/models/entities/user.js";
 import { Users } from "@/models/index.js";
 import { toPuny } from "backend-rs";
diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts
index 00c8a6babe..2de7ab1827 100644
--- a/packages/backend/src/server/activitypub.ts
+++ b/packages/backend/src/server/activitypub.ts
@@ -31,7 +31,7 @@ import Following from "./activitypub/following.js";
 import Followers from "./activitypub/followers.js";
 import Outbox, { packActivity } from "./activitypub/outbox.js";
 import { serverLogger } from "./index.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import Koa from "koa";
 import * as crypto from "node:crypto";
 import { inspect } from "node:util";
diff --git a/packages/backend/src/server/activitypub/featured.ts b/packages/backend/src/server/activitypub/featured.ts
index e7ea6f238e..671c7ac67e 100644
--- a/packages/backend/src/server/activitypub/featured.ts
+++ b/packages/backend/src/server/activitypub/featured.ts
@@ -1,5 +1,5 @@
 import { IsNull } from "typeorm";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { renderActivity } from "@/remote/activitypub/renderer/index.js";
 import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-collection.js";
 import renderNote from "@/remote/activitypub/renderer/note.js";
diff --git a/packages/backend/src/server/activitypub/followers.ts b/packages/backend/src/server/activitypub/followers.ts
index 576a672d6d..603e93ebe8 100644
--- a/packages/backend/src/server/activitypub/followers.ts
+++ b/packages/backend/src/server/activitypub/followers.ts
@@ -1,5 +1,5 @@
 import { IsNull, LessThan } from "typeorm";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import * as url from "@/prelude/url.js";
 import { renderActivity } from "@/remote/activitypub/renderer/index.js";
 import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-collection.js";
diff --git a/packages/backend/src/server/activitypub/following.ts b/packages/backend/src/server/activitypub/following.ts
index 76b4e79716..be5a4e9643 100644
--- a/packages/backend/src/server/activitypub/following.ts
+++ b/packages/backend/src/server/activitypub/following.ts
@@ -1,5 +1,5 @@
 import { LessThan, IsNull } from "typeorm";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import * as url from "@/prelude/url.js";
 import { renderActivity } from "@/remote/activitypub/renderer/index.js";
 import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-collection.js";
diff --git a/packages/backend/src/server/activitypub/outbox.ts b/packages/backend/src/server/activitypub/outbox.ts
index 305102cf12..06319565e5 100644
--- a/packages/backend/src/server/activitypub/outbox.ts
+++ b/packages/backend/src/server/activitypub/outbox.ts
@@ -1,5 +1,5 @@
 import { Brackets, IsNull } from "typeorm";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { renderActivity } from "@/remote/activitypub/renderer/index.js";
 import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-collection.js";
 import renderOrderedCollectionPage from "@/remote/activitypub/renderer/ordered-collection-page.js";
diff --git a/packages/backend/src/server/api/2fa.ts b/packages/backend/src/server/api/2fa.ts
index 7318f0f433..5a6479939d 100644
--- a/packages/backend/src/server/api/2fa.ts
+++ b/packages/backend/src/server/api/2fa.ts
@@ -1,6 +1,6 @@
 import * as crypto from "node:crypto";
 import * as jsrsasign from "jsrsasign";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 const ECC_PRELUDE = Buffer.from([0x04]);
 const NULL_BYTE = Buffer.from([0]);
diff --git a/packages/backend/src/server/api/common/signin.ts b/packages/backend/src/server/api/common/signin.ts
index e59a39ac41..e5ca09df95 100644
--- a/packages/backend/src/server/api/common/signin.ts
+++ b/packages/backend/src/server/api/common/signin.ts
@@ -1,6 +1,6 @@
 import type Koa from "koa";
 
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { ILocalUser } from "@/models/entities/user.js";
 import { Signins } from "@/models/index.js";
 import { genId } from "backend-rs";
diff --git a/packages/backend/src/server/api/common/signup.ts b/packages/backend/src/server/api/common/signup.ts
index 58b88b7d02..40b59c8ed5 100644
--- a/packages/backend/src/server/api/common/signup.ts
+++ b/packages/backend/src/server/api/common/signup.ts
@@ -8,7 +8,7 @@ import { genId, hashPassword, toPuny } from "backend-rs";
 import { UserKeypair } from "@/models/entities/user-keypair.js";
 import { UsedUsername } from "@/models/entities/used-username.js";
 import { db } from "@/db/postgre.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 export async function signup(opts: {
 	username: User["username"];
diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts b/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts
index fd4ad9401a..01d08f7a3d 100644
--- a/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts
+++ b/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { Meta } from "@/models/entities/meta.js";
 import { insertModerationLog } from "@/services/insert-moderation-log.js";
 import { db } from "@/db/postgre.js";
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index c7731c6c81..d0e639fcf1 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { fetchMeta } from "backend-rs";
 import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js";
 import define from "@/server/api/define.js";
diff --git a/packages/backend/src/server/api/endpoints/auth/session/generate.ts b/packages/backend/src/server/api/endpoints/auth/session/generate.ts
index 26a1fddfcb..f20219aa82 100644
--- a/packages/backend/src/server/api/endpoints/auth/session/generate.ts
+++ b/packages/backend/src/server/api/endpoints/auth/session/generate.ts
@@ -1,5 +1,5 @@
 import { v4 as uuid } from "uuid";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import define from "@/server/api/define.js";
 import { ApiError } from "@/server/api/error.js";
 import { Apps, AuthSessions } from "@/models/index.js";
diff --git a/packages/backend/src/server/api/endpoints/fetch-rss.ts b/packages/backend/src/server/api/endpoints/fetch-rss.ts
index bda3c455d1..489aaab0f5 100644
--- a/packages/backend/src/server/api/endpoints/fetch-rss.ts
+++ b/packages/backend/src/server/api/endpoints/fetch-rss.ts
@@ -1,6 +1,6 @@
 import Parser from "rss-parser";
 import { getResponse } from "@/misc/fetch.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import define from "@/server/api/define.js";
 
 const rssParser = new Parser();
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
index 6c99217e7d..0951369dd8 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
@@ -6,7 +6,7 @@ import {
 	AttestationChallenges,
 	Users,
 } from "@/models/index.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { procedures, hash } from "@/server/api/2fa.js";
 import { publishMainStream } from "@/services/stream.js";
 import { verifyPassword } from "backend-rs";
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/register.ts b/packages/backend/src/server/api/endpoints/i/2fa/register.ts
index c0e6137d5d..eb926a6098 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/register.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/register.ts
@@ -1,6 +1,6 @@
 import * as OTPAuth from "otpauth";
 import * as QRCode from "qrcode";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { UserProfiles } from "@/models/index.js";
 import define from "@/server/api/define.js";
 import { verifyPassword } from "backend-rs";
diff --git a/packages/backend/src/server/api/endpoints/i/move.ts b/packages/backend/src/server/api/endpoints/i/move.ts
index 4784d3ee20..381bb1dea9 100644
--- a/packages/backend/src/server/api/endpoints/i/move.ts
+++ b/packages/backend/src/server/api/endpoints/i/move.ts
@@ -10,7 +10,7 @@ import deleteFollowing from "@/services/following/delete.js";
 import create from "@/services/following/create.js";
 import { getUser } from "@/server/api/common/getters.js";
 import { Followings, Users } from "@/models/index.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { publishMainStream } from "@/services/stream.js";
 import { stringToAcct } from "backend-rs";
 import { inspect } from "node:util";
diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts
index 234127f584..185d1c8dc9 100644
--- a/packages/backend/src/server/api/endpoints/i/update-email.ts
+++ b/packages/backend/src/server/api/endpoints/i/update-email.ts
@@ -1,7 +1,7 @@
 import { publishMainStream } from "@/services/stream.js";
 import define from "@/server/api/define.js";
 import rndstr from "rndstr";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { Users, UserProfiles } from "@/models/index.js";
 import { sendEmail } from "@/services/send-email.js";
 import { ApiError } from "@/server/api/error.js";
diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 31677ee2ef..0167377944 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -1,6 +1,6 @@
 import JSON5 from "json5";
 import { IsNull, MoreThan } from "typeorm";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { fetchMeta } from "backend-rs";
 import { Ads, Emojis, Users } from "@/models/index.js";
 import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js";
diff --git a/packages/backend/src/server/api/endpoints/request-reset-password.ts b/packages/backend/src/server/api/endpoints/request-reset-password.ts
index 9855b06513..00936c9d22 100644
--- a/packages/backend/src/server/api/endpoints/request-reset-password.ts
+++ b/packages/backend/src/server/api/endpoints/request-reset-password.ts
@@ -1,6 +1,6 @@
 import rndstr from "rndstr";
 import { IsNull } from "typeorm";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { Users, UserProfiles, PasswordResetRequests } from "@/models/index.js";
 import { sendEmail } from "@/services/send-email.js";
 import { genId } from "backend-rs";
diff --git a/packages/backend/src/server/api/endpoints/username/available.ts b/packages/backend/src/server/api/endpoints/username/available.ts
index cd634a798a..3818a3c28f 100644
--- a/packages/backend/src/server/api/endpoints/username/available.ts
+++ b/packages/backend/src/server/api/endpoints/username/available.ts
@@ -1,6 +1,6 @@
 import { IsNull } from "typeorm";
 import { Users, UsedUsernames } from "@/models/index.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import define from "@/server/api/define.js";
 
 export const meta = {
diff --git a/packages/backend/src/server/api/index.ts b/packages/backend/src/server/api/index.ts
index 493661b2a2..7e5cd892bc 100644
--- a/packages/backend/src/server/api/index.ts
+++ b/packages/backend/src/server/api/index.ts
@@ -12,7 +12,7 @@ import {
 	getClient,
 } from "./mastodon/ApiMastodonCompatibleService.js";
 import { AccessTokens, Users } from "@/models/index.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import endpoints from "./endpoints.js";
 import compatibility from "./compatibility.js";
 import handler from "./api-handler.js";
diff --git a/packages/backend/src/server/api/mastodon/endpoints/meta.ts b/packages/backend/src/server/api/mastodon/endpoints/meta.ts
index 5c304929a1..862310fb3e 100644
--- a/packages/backend/src/server/api/mastodon/endpoints/meta.ts
+++ b/packages/backend/src/server/api/mastodon/endpoints/meta.ts
@@ -1,5 +1,5 @@
 import { Entity } from "megalodon";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { fetchMeta } from "backend-rs";
 import { Users, Notes } from "@/models/index.js";
 import { IsNull } from "typeorm";
diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts
index 8b2f92b745..79dc48a8bb 100644
--- a/packages/backend/src/server/api/openapi/gen-spec.ts
+++ b/packages/backend/src/server/api/openapi/gen-spec.ts
@@ -1,5 +1,5 @@
 import endpoints from "@/server/api/endpoints.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { errors as basicErrors } from "./errors.js";
 import { schemas, convertSchemaToOpenApiSchema } from "./schemas.js";
 
diff --git a/packages/backend/src/server/api/private/signin.ts b/packages/backend/src/server/api/private/signin.ts
index a7eb623062..d8bbbf74ad 100644
--- a/packages/backend/src/server/api/private/signin.ts
+++ b/packages/backend/src/server/api/private/signin.ts
@@ -1,7 +1,7 @@
 import type Koa from "koa";
 import * as OTPAuth from "otpauth";
 import signin from "@/server/api/common/signin.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import {
 	Users,
 	Signins,
diff --git a/packages/backend/src/server/api/private/signup.ts b/packages/backend/src/server/api/private/signup.ts
index 5af5d65b50..4dd4ffb231 100644
--- a/packages/backend/src/server/api/private/signup.ts
+++ b/packages/backend/src/server/api/private/signup.ts
@@ -3,7 +3,7 @@ import rndstr from "rndstr";
 import { verifyHcaptcha, verifyRecaptcha } from "@/misc/captcha.js";
 import { Users, RegistrationTickets, UserPendings } from "@/models/index.js";
 import { signup } from "@/server/api/common/signup.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { sendEmail } from "@/services/send-email.js";
 import { fetchMeta, genId, hashPassword } from "backend-rs";
 import { validateEmailForAccount } from "@/services/validate-email-for-account.js";
diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts
index 17358a4758..54d6e8bf5f 100644
--- a/packages/backend/src/server/index.ts
+++ b/packages/backend/src/server/index.ts
@@ -13,7 +13,7 @@ import koaLogger from "koa-logger";
 import * as slow from "koa-slow";
 
 import { IsNull } from "typeorm";
-import config, { envOption } from "@/config/index.js";
+import { config, envOption } from "@/config.js";
 import Logger from "@/services/logger.js";
 import { Users } from "@/models/index.js";
 import { fetchMeta } from "backend-rs";
diff --git a/packages/backend/src/server/nodeinfo.ts b/packages/backend/src/server/nodeinfo.ts
index 7359878b19..91e5fd8034 100644
--- a/packages/backend/src/server/nodeinfo.ts
+++ b/packages/backend/src/server/nodeinfo.ts
@@ -1,5 +1,5 @@
 import Router from "@koa/router";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { fetchMeta } from "backend-rs";
 import { Users, Notes } from "@/models/index.js";
 import { IsNull, MoreThan } from "typeorm";
diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts
index e6b09b4f4f..5208ee70e4 100644
--- a/packages/backend/src/server/web/feed.ts
+++ b/packages/backend/src/server/web/feed.ts
@@ -1,6 +1,6 @@
 import { Feed } from "feed";
 import { In, IsNull } from "typeorm";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 import { Notes, DriveFiles, UserProfiles, Users } from "@/models/index.js";
 
diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts
index 939fcfab14..dfc1cdc475 100644
--- a/packages/backend/src/server/web/index.ts
+++ b/packages/backend/src/server/web/index.ts
@@ -16,7 +16,7 @@ import { KoaAdapter } from "@bull-board/koa";
 
 import { In, IsNull } from "typeorm";
 import { fetchMeta, metaToPugArgs } from "backend-rs";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import {
 	Users,
 	Notes,
diff --git a/packages/backend/src/server/web/manifest.ts b/packages/backend/src/server/web/manifest.ts
index a4c615c7ab..77c8a57cf4 100644
--- a/packages/backend/src/server/web/manifest.ts
+++ b/packages/backend/src/server/web/manifest.ts
@@ -1,6 +1,6 @@
 import type Koa from "koa";
 import { fetchMeta } from "backend-rs";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import manifest from "./manifest.json" assert { type: "json" };
 
 export const manifestHandler = async (ctx: Koa.Context) => {
diff --git a/packages/backend/src/server/web/url-preview.ts b/packages/backend/src/server/web/url-preview.ts
index f59f3f357a..8fd757ef14 100644
--- a/packages/backend/src/server/web/url-preview.ts
+++ b/packages/backend/src/server/web/url-preview.ts
@@ -2,7 +2,7 @@ import type Koa from "koa";
 import summaly from "summaly";
 import { fetchMeta } from "backend-rs";
 import Logger from "@/services/logger.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { query } from "@/prelude/url.js";
 import { getJson } from "@/misc/fetch.js";
 import { inspect } from "node:util";
diff --git a/packages/backend/src/server/well-known.ts b/packages/backend/src/server/well-known.ts
index fc339eaad6..4a244db57f 100644
--- a/packages/backend/src/server/well-known.ts
+++ b/packages/backend/src/server/well-known.ts
@@ -1,6 +1,6 @@
 import Router from "@koa/router";
 
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { type Acct, stringToAcct } from "backend-rs";
 import { links } from "./nodeinfo.js";
 import { escapeAttribute, escapeValue } from "@/prelude/xml.js";
diff --git a/packages/backend/src/services/drive/internal-storage.ts b/packages/backend/src/services/drive/internal-storage.ts
index b2a663b3ea..6413f7920e 100644
--- a/packages/backend/src/services/drive/internal-storage.ts
+++ b/packages/backend/src/services/drive/internal-storage.ts
@@ -3,7 +3,7 @@ import * as fsPromises from "node:fs/promises";
 import * as Path from "node:path";
 import { fileURLToPath } from "node:url";
 import { dirname } from "node:path";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 const _filename = fileURLToPath(import.meta.url);
 const _dirname = dirname(_filename);
diff --git a/packages/backend/src/services/fetch-rel-me.ts b/packages/backend/src/services/fetch-rel-me.ts
index c9a37d1c88..e9736f8c33 100644
--- a/packages/backend/src/services/fetch-rel-me.ts
+++ b/packages/backend/src/services/fetch-rel-me.ts
@@ -1,5 +1,5 @@
 import { Window } from "happy-dom";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 async function getRelMeLinks(url: string): Promise<string[]> {
 	try {
diff --git a/packages/backend/src/services/following/requests/create.ts b/packages/backend/src/services/following/requests/create.ts
index d2f2c1ca41..146e20efd9 100644
--- a/packages/backend/src/services/following/requests/create.ts
+++ b/packages/backend/src/services/following/requests/create.ts
@@ -6,7 +6,7 @@ import type { User } from "@/models/entities/user.js";
 import { Blockings, FollowRequests, Users } from "@/models/index.js";
 import { genId } from "backend-rs";
 import { createNotification } from "@/services/create-notification.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 
 export default async function (
 	follower: {
diff --git a/packages/backend/src/services/i/pin.ts b/packages/backend/src/services/i/pin.ts
index 2d2675a535..b44ba5f9fa 100644
--- a/packages/backend/src/services/i/pin.ts
+++ b/packages/backend/src/services/i/pin.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import renderAdd from "@/remote/activitypub/renderer/add.js";
 import renderRemove from "@/remote/activitypub/renderer/remove.js";
 import { renderActivity } from "@/remote/activitypub/renderer/index.js";
diff --git a/packages/backend/src/services/logger.ts b/packages/backend/src/services/logger.ts
index e53279e31c..bd2ca74793 100644
--- a/packages/backend/src/services/logger.ts
+++ b/packages/backend/src/services/logger.ts
@@ -2,7 +2,7 @@ import cluster from "node:cluster";
 import chalk from "chalk";
 import { default as convertColor } from "color-convert";
 import { format as dateFormat } from "date-fns";
-import config, { envOption } from "@/config/index.js";
+import { config, envOption } from "@/config.js";
 
 import * as SyslogPro from "syslog-pro";
 
diff --git a/packages/backend/src/services/messages/delete.ts b/packages/backend/src/services/messages/delete.ts
index 77caba80ce..2d8f6b9baf 100644
--- a/packages/backend/src/services/messages/delete.ts
+++ b/packages/backend/src/services/messages/delete.ts
@@ -1,4 +1,4 @@
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { MessagingMessages, Users } from "@/models/index.js";
 import type { MessagingMessage } from "@/models/entities/messaging-message.js";
 import {
diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts
index 0a4ddc517f..662064da57 100644
--- a/packages/backend/src/services/note/create.ts
+++ b/packages/backend/src/services/note/create.ts
@@ -10,7 +10,7 @@ import renderCreate from "@/remote/activitypub/renderer/create.js";
 import renderAnnounce from "@/remote/activitypub/renderer/announce.js";
 import { renderActivity } from "@/remote/activitypub/renderer/index.js";
 import { resolveUser } from "@/remote/resolve-user.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { updateHashtags } from "@/services/update-hashtag.js";
 import { concat } from "@/prelude/array.js";
 import { insertNoteUnread } from "@/services/note/unread.js";
diff --git a/packages/backend/src/services/note/delete.ts b/packages/backend/src/services/note/delete.ts
index be3bf1e8b2..c709792fef 100644
--- a/packages/backend/src/services/note/delete.ts
+++ b/packages/backend/src/services/note/delete.ts
@@ -5,7 +5,7 @@ import renderAnnounce from "@/remote/activitypub/renderer/announce.js";
 import renderUndo from "@/remote/activitypub/renderer/undo.js";
 import { renderActivity } from "@/remote/activitypub/renderer/index.js";
 import renderTombstone from "@/remote/activitypub/renderer/tombstone.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js";
 import type { Note, IMentionedRemoteUsers } from "@/models/entities/note.js";
 import { Notes, Users, Instances } from "@/models/index.js";
diff --git a/packages/backend/src/services/push-notification.ts b/packages/backend/src/services/push-notification.ts
index 3f1f2cfb1a..86dd2a32e2 100644
--- a/packages/backend/src/services/push-notification.ts
+++ b/packages/backend/src/services/push-notification.ts
@@ -1,5 +1,5 @@
 import push from "web-push";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { SwSubscriptions } from "@/models/index.js";
 import { fetchMeta, getNoteSummary } from "backend-rs";
 import type { Packed } from "@/misc/schema.js";
diff --git a/packages/backend/src/services/send-email.ts b/packages/backend/src/services/send-email.ts
index 11a899d267..bcbecce356 100644
--- a/packages/backend/src/services/send-email.ts
+++ b/packages/backend/src/services/send-email.ts
@@ -1,7 +1,7 @@
 import * as nodemailer from "nodemailer";
 import { fetchMeta } from "backend-rs";
 import Logger from "@/services/logger.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import { inspect } from "node:util";
 
 export const logger = new Logger("email");
diff --git a/packages/backend/src/services/stream.ts b/packages/backend/src/services/stream.ts
index bd09bc3f2c..0e2395e87e 100644
--- a/packages/backend/src/services/stream.ts
+++ b/packages/backend/src/services/stream.ts
@@ -3,7 +3,7 @@ import type { User } from "@/models/entities/user.js";
 import type { Note } from "@/models/entities/note.js";
 import type { UserList } from "@/models/entities/user-list.js";
 import type { UserGroup } from "@/models/entities/user-group.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { Antenna } from "@/models/entities/antenna.js";
 import type { Channel } from "@/models/entities/channel.js";
 import type {
diff --git a/packages/backend/src/services/suspend-user.ts b/packages/backend/src/services/suspend-user.ts
index f72b8ffcb1..0babd31bc5 100644
--- a/packages/backend/src/services/suspend-user.ts
+++ b/packages/backend/src/services/suspend-user.ts
@@ -1,7 +1,7 @@
 import renderDelete from "@/remote/activitypub/renderer/delete.js";
 import { renderActivity } from "@/remote/activitypub/renderer/index.js";
 import { deliver } from "@/queue/index.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 import { Users, Followings } from "@/models/index.js";
 import { Not, IsNull } from "typeorm";
diff --git a/packages/backend/src/services/unsuspend-user.ts b/packages/backend/src/services/unsuspend-user.ts
index 69447a4a26..72d7e30d66 100644
--- a/packages/backend/src/services/unsuspend-user.ts
+++ b/packages/backend/src/services/unsuspend-user.ts
@@ -2,7 +2,7 @@ import renderDelete from "@/remote/activitypub/renderer/delete.js";
 import renderUndo from "@/remote/activitypub/renderer/undo.js";
 import { renderActivity } from "@/remote/activitypub/renderer/index.js";
 import { deliver } from "@/queue/index.js";
-import config from "@/config/index.js";
+import { config } from "@/config.js";
 import type { User } from "@/models/entities/user.js";
 import { Users, Followings } from "@/models/index.js";
 import { Not, IsNull } from "typeorm";