mirror of
https://github.com/wireadmin/wireadmin
synced 2025-03-09 21:30:14 +00:00
Create a new field within WGServer
that will monitor any modifications made to the wg
configuration files. Furthermore, implement a health check for the container.
This commit is contained in:
parent
8ab5b0b0fc
commit
3928a84677
@ -50,6 +50,9 @@ RUN npm install --omit dev
|
|||||||
|
|
||||||
EXPOSE 3000/tcp
|
EXPOSE 3000/tcp
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
|
CMD curl -f http://127.0.0.1:3000/api/wireguard/healthcheck || exit 1
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /usr/bin/entrypoint
|
COPY docker-entrypoint.sh /usr/bin/entrypoint
|
||||||
RUN chmod +x /usr/bin/entrypoint
|
RUN chmod +x /usr/bin/entrypoint
|
||||||
ENTRYPOINT ["/usr/bin/entrypoint"]
|
ENTRYPOINT ["/usr/bin/entrypoint"]
|
||||||
|
@ -28,6 +28,9 @@ COPY /config/torrc /etc/tor/torrc
|
|||||||
|
|
||||||
EXPOSE 3000/tcp
|
EXPOSE 3000/tcp
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
|
CMD curl -f http://127.0.0.1:3000/api/wireguard/healthcheck || exit 1
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /usr/bin/entrypoint
|
COPY docker-entrypoint.sh /usr/bin/entrypoint
|
||||||
RUN chmod +x /usr/bin/entrypoint
|
RUN chmod +x /usr/bin/entrypoint
|
||||||
ENTRYPOINT ["/usr/bin/entrypoint"]
|
ENTRYPOINT ["/usr/bin/entrypoint"]
|
||||||
|
@ -91,6 +91,6 @@ echo -e "========================================================\n"
|
|||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
# After 10 seconds, export the database to the WireGuard config file
|
# After 10 seconds, export the database to the WireGuard config file
|
||||||
screen -dm bash -c "sleep 10; curl -s -o /dev/null http://127.0.0.1:3000/api/wireguard/regen"
|
screen -dm bash -c "sleep 10; curl -s -o /dev/null http://127.0.0.1:3000/api/wireguard/healthcheck"
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:image": "cross-env DOCKER_BUILDKIT=1 docker build --tag wireadmin -f Dockerfile-Dev .",
|
"dev:image": "cross-env DOCKER_BUILDKIT=1 docker build --tag wireadmin -f Dockerfile-Dev .",
|
||||||
"dev": "docker-compose -f docker-compose.yml -f docker-compose.dev.yml up"
|
"dev": "docker-compose -f docker-compose.yml -f docker-compose.dev.yml up; docker rm -f wireadmin"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Shahrad Elahi <https://github.com/shahradelahi>",
|
"author": "Shahrad Elahi <https://github.com/shahradelahi>",
|
||||||
|
@ -44,6 +44,7 @@ export type Peer = z.infer<typeof PeerSchema>
|
|||||||
export const WgServerSchema = z.object({
|
export const WgServerSchema = z.object({
|
||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
confId: z.number(),
|
confId: z.number(),
|
||||||
|
confHash: z.string().nullable(),
|
||||||
type: z.enum([ 'direct', 'bridge', 'tor' ]),
|
type: z.enum([ 'direct', 'bridge', 'tor' ]),
|
||||||
name: NameSchema,
|
name: NameSchema,
|
||||||
address: z.string().regex(IPV4_REGEX),
|
address: z.string().regex(IPV4_REGEX),
|
||||||
|
@ -8,6 +8,7 @@ import { dynaJoin, isJson } from "@lib/utils";
|
|||||||
import deepmerge from "deepmerge";
|
import deepmerge from "deepmerge";
|
||||||
import { getPeerConf } from "@lib/wireguard-utils";
|
import { getPeerConf } from "@lib/wireguard-utils";
|
||||||
import Network from "@lib/network";
|
import Network from "@lib/network";
|
||||||
|
import { SHA256 } from "crypto-js";
|
||||||
|
|
||||||
export class WGServer {
|
export class WGServer {
|
||||||
|
|
||||||
@ -108,6 +109,7 @@ export class WGServer {
|
|||||||
peer.persistentKeepalive && `PersistentKeepalive = ${peer.persistentKeepalive}`
|
peer.persistentKeepalive && `PersistentKeepalive = ${peer.persistentKeepalive}`
|
||||||
]))
|
]))
|
||||||
await fs.writeFile(confPath, lines.join('\n'))
|
await fs.writeFile(confPath, lines.join('\n'))
|
||||||
|
await WGServer.update(id, { confHash: await getConfigHash(id) });
|
||||||
|
|
||||||
const index = await findServerIndex(id)
|
const index = await findServerIndex(id)
|
||||||
if (typeof index !== 'number') {
|
if (typeof index !== 'number') {
|
||||||
@ -155,6 +157,7 @@ export class WGServer {
|
|||||||
conf
|
conf
|
||||||
const peersStr = peers.filter((_, i) => i !== peerIndex).join('\n')
|
const peersStr = peers.filter((_, i) => i !== peerIndex).join('\n')
|
||||||
await fs.writeFile(confPath, `${serverConfStr}\n${peersStr}`)
|
await fs.writeFile(confPath, `${serverConfStr}\n${peersStr}`)
|
||||||
|
await WGServer.update(server.id, { confHash: await getConfigHash(server.id) });
|
||||||
|
|
||||||
await WGServer.stop(server.id)
|
await WGServer.stop(server.id)
|
||||||
await WGServer.start(server.id)
|
await WGServer.start(server.id)
|
||||||
@ -214,6 +217,7 @@ export class WGServer {
|
|||||||
|
|
||||||
const peersStr = peers.filter((_, i) => i !== peerIndex).join('\n')
|
const peersStr = peers.filter((_, i) => i !== peerIndex).join('\n')
|
||||||
await fs.writeFile(confPath, `${serverConfStr}\n${peersStr}`)
|
await fs.writeFile(confPath, `${serverConfStr}\n${peersStr}`)
|
||||||
|
await WGServer.update(sd.id, { confHash: await getConfigHash(sd.id) });
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getFreePeerIp(id: string): Promise<string | undefined> {
|
static async getFreePeerIp(id: string): Promise<string | undefined> {
|
||||||
@ -271,6 +275,7 @@ export async function readWgConf(configId: number): Promise<WgServer> {
|
|||||||
const server: WgServer = {
|
const server: WgServer = {
|
||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
confId: configId,
|
confId: configId,
|
||||||
|
confHash: null,
|
||||||
type: 'direct',
|
type: 'direct',
|
||||||
name: '',
|
name: '',
|
||||||
address: '',
|
address: '',
|
||||||
@ -416,6 +421,7 @@ export async function generateWgServer(config: {
|
|||||||
let server: WgServer = {
|
let server: WgServer = {
|
||||||
id: uuid,
|
id: uuid,
|
||||||
confId,
|
confId,
|
||||||
|
confHash: null,
|
||||||
type: config.type,
|
type: config.type,
|
||||||
name: config.name,
|
name: config.name,
|
||||||
address: config.address,
|
address: config.address,
|
||||||
@ -459,9 +465,10 @@ export async function generateWgServer(config: {
|
|||||||
const CONFIG_PATH = path.join(WG_PATH, `wg${confId}.conf`)
|
const CONFIG_PATH = path.join(WG_PATH, `wg${confId}.conf`)
|
||||||
|
|
||||||
// save server config to disk
|
// save server config to disk
|
||||||
await fs.writeFile(CONFIG_PATH, await genServerConf(server), {
|
await fs.writeFile(CONFIG_PATH, await genServerConf(server), { mode: 0o600 })
|
||||||
mode: 0o600,
|
|
||||||
})
|
// updating hash of the config
|
||||||
|
await WGServer.update(uuid, { confHash: await getConfigHash(uuid) });
|
||||||
|
|
||||||
// to ensure interface does not exists
|
// to ensure interface does not exists
|
||||||
await Shell.exec(`wg-quick down wg${confId}`, true)
|
await Shell.exec(`wg-quick down wg${confId}`, true)
|
||||||
@ -473,6 +480,23 @@ export async function generateWgServer(config: {
|
|||||||
return uuid
|
return uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getConfigHash(id: string): Promise<string | undefined> {
|
||||||
|
const server = await findServer(id)
|
||||||
|
if (!server) {
|
||||||
|
console.error('getConfigHash: server not found')
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
const confPath = path.join(WG_PATH, `wg${server.confId}.conf`)
|
||||||
|
const conf = await fs.readFile(confPath, 'utf-8')
|
||||||
|
return CryptoJS.enc.Hex.stringify(SHA256(conf));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function writeConfigFile(wg: WgServer): Promise<void> {
|
||||||
|
const CONFIG_PATH = path.join(WG_PATH, `wg${wg.confId}.conf`)
|
||||||
|
await fs.writeFile(CONFIG_PATH, await genServerConf(wg), { mode: 0o600 })
|
||||||
|
await WGServer.update(wg.id, { confHash: await getConfigHash(wg.id) });
|
||||||
|
}
|
||||||
|
|
||||||
export async function maxConfId(): Promise<number> {
|
export async function maxConfId(): Promise<number> {
|
||||||
// get files in /etc/wireguard
|
// get files in /etc/wireguard
|
||||||
const files = await fs.readdir(WG_PATH)
|
const files = await fs.readdir(WG_PATH)
|
||||||
|
27
src/pages/api/wireguard/healthcheck.ts
Normal file
27
src/pages/api/wireguard/healthcheck.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||||
|
import safeServe from "@lib/safe-serve";
|
||||||
|
import { getConfigHash, getServers, WGServer, writeConfigFile } from "@lib/wireguard";
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
return safeServe(res, async () => {
|
||||||
|
|
||||||
|
const servers = await getServers()
|
||||||
|
|
||||||
|
for (const s of servers) {
|
||||||
|
|
||||||
|
const HASH = await getConfigHash(s.id);
|
||||||
|
if (s.confId && s.confHash === HASH) {
|
||||||
|
// Skip, due to no changes on the config
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await writeConfigFile(s);
|
||||||
|
await WGServer.start(s.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
.status(200)
|
||||||
|
.end('OK')
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
@ -1,30 +0,0 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
|
||||||
import safeServe from "@lib/safe-serve";
|
|
||||||
import { genServerConf, getServers, WGServer } from "@lib/wireguard";
|
|
||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import { WG_PATH } from "@lib/constants";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This API Endpoint is for recreating WireGuard's configs from the database.
|
|
||||||
*
|
|
||||||
* @param req
|
|
||||||
* @param res
|
|
||||||
*/
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
||||||
return safeServe(res, async () => {
|
|
||||||
|
|
||||||
const servers = await getServers()
|
|
||||||
|
|
||||||
for (const s of servers) {
|
|
||||||
const CONFIG_PATH = path.join(WG_PATH, `wg${s.confId}.conf`)
|
|
||||||
fs.writeFileSync(CONFIG_PATH, await genServerConf(s), { mode: 0o600 })
|
|
||||||
await WGServer.start(s.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
.status(200)
|
|
||||||
.end('OK')
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user