mirror of
https://github.com/wireadmin/wireadmin
synced 2025-04-27 17:32:01 +00:00
After restarting container, it will try to regenerate WireGuard
conf from Database
This commit is contained in:
parent
34050ed173
commit
734b0c8e02
@ -12,7 +12,7 @@ ulimit -c 0
|
|||||||
# Checking if there is /data folder
|
# Checking if there is /data folder
|
||||||
if [ ! -d "/data" ]; then
|
if [ ! -d "/data" ]; then
|
||||||
mkdir -p /data
|
mkdir -p /data
|
||||||
chmod 744 /data
|
chmod 700 /data
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Starting Redis server in detached mode
|
# Starting Redis server in detached mode
|
||||||
@ -26,4 +26,7 @@ if [ ! -z "$WG_HOST" ]; then
|
|||||||
export NEXT_PUBLIC_WG_HOST=$WG_HOST
|
export NEXT_PUBLIC_WG_HOST=$WG_HOST
|
||||||
fi
|
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 "$@"
|
exec "$@"
|
||||||
|
@ -4,7 +4,7 @@ export default class Shell {
|
|||||||
|
|
||||||
public static async exec(command: string, safe: boolean = false, ...args: string[]): Promise<string> {
|
public static async exec(command: string, safe: boolean = false, ...args: string[]): Promise<string> {
|
||||||
if (process.platform !== 'linux') {
|
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) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
const cmd = `${command}${args.length > 0 ? ` ${args.join(' ')}` : ''}`;
|
const cmd = `${command}${args.length > 0 ? ` ${args.join(' ')}` : ''}`;
|
||||||
|
@ -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\.)/
|
const ipRegex = /^(127\.)|(10\.)|(172\.1[6-9]\.)|(172\.2[0-9]\.)|(172\.3[0-1]\.)|(192\.168\.)/
|
||||||
return ipRegex.test(ip)
|
return ipRegex.test(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function dynaJoin(lines: (string | 0 | null | undefined)[]): string[] {
|
||||||
|
return lines.filter((d) => typeof d === 'string') as string[]
|
||||||
|
}
|
@ -13,16 +13,16 @@ export function getServerConf(server: WgServer): string {
|
|||||||
`${server.postUp ? `PostUp = ${server.postUp}` : 'OMIT'}`,
|
`${server.postUp ? `PostUp = ${server.postUp}` : 'OMIT'}`,
|
||||||
`${server.preDown ? `PreDown = ${server.preDown}` : 'OMIT'}`,
|
`${server.preDown ? `PreDown = ${server.preDown}` : 'OMIT'}`,
|
||||||
`${server.postDown ? `PostDown = ${server.postDown}` : '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
|
return lines
|
||||||
.filter((l) => l !== 'OMIT')
|
.filter((l) => l !== 'OMIT')
|
||||||
.join('\n')
|
.join('\n')
|
||||||
|
@ -4,7 +4,7 @@ import { WG_PATH } from "@lib/constants";
|
|||||||
import Shell from "@lib/shell";
|
import Shell from "@lib/shell";
|
||||||
import { WgKey, WgServer } from "@lib/typings";
|
import { WgKey, WgServer } from "@lib/typings";
|
||||||
import { client, WG_SEVER_PATH } from "@lib/redis";
|
import { client, WG_SEVER_PATH } from "@lib/redis";
|
||||||
import { isJson } from "@lib/utils";
|
import { dynaJoin, isJson } from "@lib/utils";
|
||||||
import deepmerge from "deepmerge";
|
import deepmerge from "deepmerge";
|
||||||
import { getPeerConf, getServerConf } from "@lib/wireguard-utils";
|
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({
|
const res = await client.lset(WG_SEVER_PATH, index, JSON.stringify({
|
||||||
...deepmerge(server, update),
|
...deepmerge(server, update),
|
||||||
|
peers: update?.peers || server?.peers || [],
|
||||||
updatedAt: new Date().toISOString()
|
updatedAt: new Date().toISOString()
|
||||||
}))
|
}))
|
||||||
return res === 'OK'
|
return res === 'OK'
|
||||||
@ -82,27 +83,32 @@ export class WGServer {
|
|||||||
console.error('server could not be updated (reason: not exists)')
|
console.error('server could not be updated (reason: not exists)')
|
||||||
return false
|
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 confPath = path.join(WG_PATH, `wg${server.confId}.conf`)
|
||||||
const conf = await fs.readFile(confPath, 'utf-8')
|
const conf = await fs.readFile(confPath, 'utf-8')
|
||||||
const lines = conf.split('\n')
|
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 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 ]
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,6 +333,7 @@ export async function generateWgServer(config: {
|
|||||||
port: number
|
port: number
|
||||||
dns?: string
|
dns?: string
|
||||||
mtu?: number
|
mtu?: number
|
||||||
|
insertDb?: boolean
|
||||||
}): Promise<string> {
|
}): Promise<string> {
|
||||||
|
|
||||||
const { privateKey, publicKey } = await generateWgKey();
|
const { privateKey, publicKey } = await generateWgKey();
|
||||||
@ -369,7 +376,9 @@ export async function generateWgServer(config: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// save server 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`)
|
const CONFIG_PATH = path.join(WG_PATH, `wg${confId}.conf`)
|
||||||
|
|
||||||
|
@ -252,11 +252,15 @@ function Client(props: ClientProps) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
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'} />
|
<QRCodeModal ref={qrcodeRef} content={conf?.trim() || 'null'} />
|
||||||
<div className={'w-full grid grid-cols-12 items-center gap-x-2'}>
|
<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'} />
|
<div className={'col-span-12 md:col-span-4'}>
|
||||||
<span className={'font-medium col-span-4'}> {props.name} </span>
|
<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>
|
||||||
<div className={'flex items-center justify-center gap-x-3'}>
|
<div className={'flex items-center justify-center gap-x-3'}>
|
||||||
{/* QRCode */}
|
{/* QRCode */}
|
||||||
|
30
src/pages/api/wireguard/regen.ts
Normal file
30
src/pages/api/wireguard/regen.ts
Normal 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')
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user