After restarting container, it will try to regenerate WireGuard conf from Database

This commit is contained in:
Shahrad Elahi 2023-09-26 03:01:07 +03:30
parent 34050ed173
commit 734b0c8e02
7 changed files with 82 additions and 32 deletions

View File

@ -12,7 +12,7 @@ ulimit -c 0
# Checking if there is /data folder
if [ ! -d "/data" ]; then
mkdir -p /data
chmod 744 /data
chmod 700 /data
fi
# Starting Redis server in detached mode
@ -26,4 +26,7 @@ if [ ! -z "$WG_HOST" ]; then
export NEXT_PUBLIC_WG_HOST=$WG_HOST
fi
# After 5 seconds, export the database to the WireGuard config file
screen -dm bash -c "sleep 5; curl -s -o /dev/null http://127.0.0.1:3000/api/wireguard/regen"
exec "$@"

View File

@ -4,7 +4,7 @@ export default class Shell {
public static async exec(command: string, safe: boolean = false, ...args: string[]): Promise<string> {
if (process.platform !== 'linux') {
throw new Error('This program is not meant to run on UNIX systems');
throw new Error('This program is not meant to run non UNIX systems');
}
return new Promise(async (resolve, reject) => {
const cmd = `${command}${args.length > 0 ? ` ${args.join(' ')}` : ''}`;

View File

@ -39,3 +39,7 @@ export function isPrivateIP(ip: string) {
const ipRegex = /^(127\.)|(10\.)|(172\.1[6-9]\.)|(172\.2[0-9]\.)|(172\.3[0-1]\.)|(192\.168\.)/
return ipRegex.test(ip)
}
export function dynaJoin(lines: (string | 0 | null | undefined)[]): string[] {
return lines.filter((d) => typeof d === 'string') as string[]
}

View File

@ -13,16 +13,16 @@ export function getServerConf(server: WgServer): string {
`${server.postUp ? `PostUp = ${server.postUp}` : 'OMIT'}`,
`${server.preDown ? `PreDown = ${server.preDown}` : 'OMIT'}`,
`${server.postDown ? `PostDown = ${server.postDown}` : 'OMIT'}`,
...server.peers.map((peer, index) => ([
'',
`## ${peer.name || `Peer #${index + 1}`}`,
'[Peer]',
`PublicKey = ${peer.publicKey}`,
`${peer.preSharedKey ? `PresharedKey = ${peer.preSharedKey}` : 'OMIT'}`,
`AllowedIPs = ${peer.allowedIps}/32`,
`${peer.persistentKeepalive ? `PersistentKeepalive = ${peer.persistentKeepalive}` : 'OMIT'}`
]))
]
server.peers.forEach((peer, index) => {
lines.push('')
lines.push(`## ${peer.name || `Peer #${index + 1}`}`)
lines.push('[Peer]')
lines.push(`PublicKey = ${peer.publicKey}`)
lines.push(`${peer.preSharedKey ? `PresharedKey = ${peer.preSharedKey}` : 'OMIT'}`)
lines.push(`AllowedIPs = ${peer.allowedIps}/32`)
lines.push(`${peer.persistentKeepalive ? `PersistentKeepalive = ${peer.persistentKeepalive}` : 'OMIT'}`)
})
return lines
.filter((l) => l !== 'OMIT')
.join('\n')

View File

@ -4,7 +4,7 @@ import { WG_PATH } from "@lib/constants";
import Shell from "@lib/shell";
import { WgKey, WgServer } from "@lib/typings";
import { client, WG_SEVER_PATH } from "@lib/redis";
import { isJson } from "@lib/utils";
import { dynaJoin, isJson } from "@lib/utils";
import deepmerge from "deepmerge";
import { getPeerConf, getServerConf } from "@lib/wireguard-utils";
@ -66,6 +66,7 @@ export class WGServer {
}
const res = await client.lset(WG_SEVER_PATH, index, JSON.stringify({
...deepmerge(server, update),
peers: update?.peers || server?.peers || [],
updatedAt: new Date().toISOString()
}))
return res === 'OK'
@ -82,27 +83,32 @@ export class WGServer {
console.error('server could not be updated (reason: not exists)')
return false
}
const peerLines = [
`[Peer]`,
`PublicKey = ${peer.publicKey}`,
`AllowedIPs = ${peer.allowedIps}/32`
]
if (peer.persistentKeepalive) {
peerLines.push(`PersistentKeepalive = ${peer.persistentKeepalive}`)
}
if (peer.preSharedKey) {
peerLines.push(`PresharedKey = ${peer.preSharedKey}`)
}
const confPath = path.join(WG_PATH, `wg${server.confId}.conf`)
const conf = await fs.readFile(confPath, 'utf-8')
const lines = conf.split('\n')
lines.push(...peerLines)
lines.push(...dynaJoin([
`[Peer]`,
`PublicKey = ${peer.publicKey}`,
peer.preSharedKey && `PresharedKey = ${peer.preSharedKey}`,
`AllowedIPs = ${peer.allowedIps}/32`,
peer.persistentKeepalive && `PersistentKeepalive = ${peer.persistentKeepalive}`
]))
await fs.writeFile(confPath, lines.join('\n'))
await WGServer.update(server.id, {
const index = await findServerIndex(id)
if (typeof index !== 'number') {
console.warn('findServerIndex: index not found')
return true
}
await client.lset(WG_SEVER_PATH, index, JSON.stringify({
...server,
peers: [ ...server.peers, peer ]
})
await WGServer.stop(server.id)
await WGServer.start(server.id)
}))
await this.stop(server.id)
await this.start(server.id)
return true
}
@ -327,6 +333,7 @@ export async function generateWgServer(config: {
port: number
dns?: string
mtu?: number
insertDb?: boolean
}): Promise<string> {
const { privateKey, publicKey } = await generateWgKey();
@ -369,7 +376,9 @@ export async function generateWgServer(config: {
}
// save server config
await client.lpush(WG_SEVER_PATH, JSON.stringify(server))
if (false !== config.insertDb) {
await client.lpush(WG_SEVER_PATH, JSON.stringify(server))
}
const CONFIG_PATH = path.join(WG_PATH, `wg${confId}.conf`)

View File

@ -252,11 +252,15 @@ function Client(props: ClientProps) {
)
return (
<List.Item className={'flex items-center justify-between p-4'}>
<List.Item key={props.id} className={'flex items-center justify-between p-4'}>
<QRCodeModal ref={qrcodeRef} content={conf?.trim() || 'null'} />
<div className={'w-full grid grid-cols-12 items-center gap-x-2'}>
<div className={'col-span-1 rounded-full bg-gray-200 aspect-square'} />
<span className={'font-medium col-span-4'}> {props.name} </span>
<div className={'col-span-12 md:col-span-4'}>
<span className={'inline-block font-medium'}> {props.name} </span>
</div>
<div className={'col-span-12 md:col-span-4'}>
<span className={'font-mono text-gray-400 text-sm'}> {props.allowedIps} </span>
</div>
</div>
<div className={'flex items-center justify-center gap-x-3'}>
{/* QRCode */}

View File

@ -0,0 +1,30 @@
import type { NextApiRequest, NextApiResponse } from 'next'
import safeServe from "@lib/safe-serve";
import { getServers } from "@lib/wireguard";
import { getServerConf } from "@lib/wireguard-utils";
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()
servers.forEach((s) => {
const CONFIG_PATH = path.join(WG_PATH, `wg${s.confId}.conf`)
fs.writeFileSync(CONFIG_PATH, getServerConf(s), { mode: 0o600 })
})
return res
.status(200)
.end('OK')
})
}