Switch to Caddy

This commit is contained in:
AaronDewes 2023-02-23 20:37:33 +00:00
parent 0507684211
commit 2999eb0931
17 changed files with 249 additions and 328 deletions

4
.gitignore vendored
View File

@ -21,7 +21,7 @@ db/*
statuses/*
app-data
apps
nginx/*
caddy/*
i2p/*
docker-compose.override.yml
@ -39,7 +39,7 @@ db/citadel-seed/*
!tor/run/.gitkeep
!tor/.gitkeep
!db/.gitkeep
!nginx/.gitkeep
!caddy/.gitkeep
!i2p/.gitkeep
!**/*.license

76
apps/stores.yml Normal file
View File

@ -0,0 +1,76 @@
- id: citadel
name: Citadel app store
tagline: The official app store by the Citadel team
icon: https://icons.runcitadel.space/app-stores/main.svg
developers: The Citadel developers
license: AGPL-3.0-or-later
apps:
lightning-terminal: 76bfe58c1b6cbc2ea23309c3217750318ac27075
code-server: 76bfe58c1b6cbc2ea23309c3217750318ac27075
lightning-shell: 76bfe58c1b6cbc2ea23309c3217750318ac27075
lnmarkets: a819714e71f3ab24c15dda4110cde0e6da0c8c42
mempool: 3fed81a6ff73bf1600ff4132bfe82d04660c0aae
bitcartcc: 3fed81a6ff73bf1600ff4132bfe82d04660c0aae
lnme: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
robosats: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
btcpay-server: 76bfe58c1b6cbc2ea23309c3217750318ac27075
thunderhub: 39433b0675a1b43e9ecbbfad6c8cc82b12667fac
synapse-admin: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
btc-rpc-explorer: 76bfe58c1b6cbc2ea23309c3217750318ac27075
node-red: 3fed81a6ff73bf1600ff4132bfe82d04660c0aae
gitea: cc93b09639e3cfc5c271be5f34073d2afe29809c
nextcloud: 6ff003d693753a021bb104d091c6c7a50e438e4d
sphinx-relay: d62423ec8ed163fe4e689dc7d6e019324a86dc56
specter-desktop: 153e2dbd1b6827f2bcd4756d1932101af0bbfac4
oak-node: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
tallycoin-connect: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
btc-rpc-explorer-public-fast: 76bfe58c1b6cbc2ea23309c3217750318ac27075
agora: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
kollider: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
lndhub: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
woofbot: 931bcab746129838ad539b2d535786865e2bd7a4
wordpress: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
krystal-bull: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
snowflake: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
ride-the-lightning: 153e2dbd1b6827f2bcd4756d1932101af0bbfac4
lnbits: db645071fd1241ca35eb2ffa42d5309884f1ed4d
ringtools: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
usocial: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
vaultwarden: d901ad3315853224c7c77d6b61ef850c14e255bb
squeaknode: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
itchysats: 3fed81a6ff73bf1600ff4132bfe82d04660c0aae
fulcrum: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
jam: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
nostr-relay: 132fb6d853f905431ea3c20097fa06e5e04a505a
electrs: 29bacf5a4b571d1e4b0e49e85ff9c219a551b76e
bluewallet: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
lnplus: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
ln-visualizer: 22b6f7e549a8e772dbf9f594dce66487ef0fd698
lndg: 53b0aae0f8cb7364ace04f7282118358744c89ce
bitfeed: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
element: 36315f17b00450eea62e8d525a670a629ab1ebf8
tailscale: 14eddca042802891b02e0d5f8999a2a1dd40c080
synapse: 996b62274dabea9653852aa57b575d3b97ed96c5
btc-rpc-explorer-public: 76bfe58c1b6cbc2ea23309c3217750318ac27075
uptime-kuma: 8500658ad8bc5c869c9e17d14a8b668b5d51ffaf
spigot-mc: 974ac0549be3c6038dcd2bb0705bb6b722a8b4ff
commit: 14eddca042802891b02e0d5f8999a2a1dd40c080
repo: https://github.com/citadel-core/apps
branch: main
subdir: v4
- id: citadel
name: Citadel app store
tagline: The official app store by the Citadel team
icon: https://icons.runcitadel.space/app-stores/main.svg
developers: The Citadel developers
license: Proprietary
apps:
samourai-server: 496d384c754d5e68dc03c8390e8e81b8ee9dc125
photoprism: 496d384c754d5e68dc03c8390e8e81b8ee9dc125
simple-torrent: 496d384c754d5e68dc03c8390e8e81b8ee9dc125
home-assistant: 496d384c754d5e68dc03c8390e8e81b8ee9dc125
pi-hole: 496d384c754d5e68dc03c8390e8e81b8ee9dc125
commit: 496d384c754d5e68dc03c8390e8e81b8ee9dc125
repo: https://github.com/citadel-core/apps-nonfree
branch: main
subdir: v4

View File

@ -330,11 +330,11 @@ if [[ "$command" = "configure" ]]; then
exit
fi
if [[ "$2" = "nginx" ]]; then
edit_file $CITADEL_ROOT/nginx/nginx.conf
prompt_apply_config nginx false
exit
fi
#if [[ "$2" = "nginx" ]]; then
#edit_file $CITADEL_ROOT/nginx/nginx.conf
#prompt_apply_config nginx false
#exit
#fi
if $persist; then
echo "NOTE: As of now persisted config changes will not be kept when updating Citadel."

View File

@ -3,8 +3,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later
compose: v2.12.2
dashboard: ghcr.io/runcitadel/dashboard:citadel-0.0.10@sha256:8920719b77a1db517e60742d72a4b63230f170d980d116f8e01974247e8da148
manager: ghcr.io/citadel-core/api:main@sha256:720a6ab0c0ada97e57186519b6c22f5a1d58ab5301e967363b905113a6cbe068
middleware: ghcr.io/runcitadel/middleware:main@sha256:b18065b02fffca0facef456109cf0de1b6cb4391f6b2186b6cd467ce6caf7642
app-cli: ghcr.io/citadel-core/app-manager:main@sha256:0e029661c7918921c3fcc4b18b9a07ed431ab47d608f35d2365da20eb58667a9
tor: lncm/tor:0.4.7.9@sha256:86c2fe9d9099e6376798979110b8b9a3ee5d8adec27289ac4a5ee892514ffe92
dashboard: ghcr.io/runcitadel/dashboard:no-https@sha256:7fc5a5b70496240e6e48a381e8ac3c7978e7343285fda4951c00846580d6216d
manager: runcitadel/api:main@sha256:12d299d8850d830fa5abd0e64c8537dfcbaec662de18376b0d7b01fa59895132
middleware: ghcr.io/runcitadel/middleware:main@sha256:cbd5fd2ab5afe420025c61e276d21c79a004d6148b8dfdd58649adb55907682b
app-cli: runcitadel/app-manager:backports@sha256:dde9197ed141e516f8300bbcdf76915366eacdda65639522d9358d4d1420a673
tor: ghcr.io/runcitadel/tor-latest:main@sha256:761948a86f8367238eb61f991cf87094b12a8a772be0eabec00d66164d13075f

View File

@ -1,11 +1,7 @@
# SPDX-FileCopyrightText: 2022 Citadel and contributors
#
# SPDX-License-Identifier: GPL-3.0-or-later
services:
tor:
container_name: tor
image: lncm/tor:0.4.7.9@sha256:86c2fe9d9099e6376798979110b8b9a3ee5d8adec27289ac4a5ee892514ffe92
image: ghcr.io/runcitadel/tor-latest:main@sha256:761948a86f8367238eb61f991cf87094b12a8a772be0eabec00d66164d13075f
user: toruser
restart: on-failure
volumes:
@ -16,9 +12,11 @@ services:
networks:
default:
ipv4_address: $TOR_PROXY_IP
extra_hosts:
- host.docker.internal:host-gateway
app-tor:
container_name: app-tor
image: lncm/tor:0.4.7.9@sha256:86c2fe9d9099e6376798979110b8b9a3ee5d8adec27289ac4a5ee892514ffe92
image: ghcr.io/runcitadel/tor-latest:main@sha256:761948a86f8367238eb61f991cf87094b12a8a772be0eabec00d66164d13075f
user: toruser
restart: on-failure
volumes:
@ -27,9 +25,11 @@ services:
networks:
default:
ipv4_address: $APPS_TOR_IP
extra_hosts:
- host.docker.internal:host-gateway
app-2-tor:
container_name: app-2-tor
image: lncm/tor:0.4.7.9@sha256:86c2fe9d9099e6376798979110b8b9a3ee5d8adec27289ac4a5ee892514ffe92
image: ghcr.io/runcitadel/tor-latest:main@sha256:761948a86f8367238eb61f991cf87094b12a8a772be0eabec00d66164d13075f
user: toruser
restart: on-failure
volumes:
@ -38,9 +38,11 @@ services:
networks:
default:
ipv4_address: $APPS_2_TOR_IP
extra_hosts:
- host.docker.internal:host-gateway
app-3-tor:
container_name: app-3-tor
image: lncm/tor:0.4.7.9@sha256:86c2fe9d9099e6376798979110b8b9a3ee5d8adec27289ac4a5ee892514ffe92
image: ghcr.io/runcitadel/tor-latest:main@sha256:761948a86f8367238eb61f991cf87094b12a8a772be0eabec00d66164d13075f
user: toruser
restart: on-failure
volumes:
@ -49,22 +51,17 @@ services:
networks:
default:
ipv4_address: $APPS_3_TOR_IP
nginx:
container_name: nginx
image: nginx:1.21.6@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
depends_on:
- dashboard
extra_hosts:
- host.docker.internal:host-gateway
caddy:
container_name: caddy
image: ghcr.io/runcitadel/caddy:main@sha256:a64ed99ad821ab53119c5e314aab47b37406c5d6caf1ec0bcd65c8da981823d8
volumes:
- ${PWD}/nginx:/etc/nginx
- ${PWD}/caddy/data:/data
- ${PWD}/caddy/Caddyfile:/etc/caddy/Caddyfile
restart: on-failure
stop_grace_period: 30s
ports:
- ${NGINX_PORT}:80
- 433:433
- ${NGINX_SSL_PORT}:443
networks:
default:
ipv4_address: $NGINX_IP
network_mode: host
bitcoin:
container_name: bitcoin
image: ghcr.io/runcitadel/bitcoinknots:main@sha256:5fbee0f6f0d09d42aacc11c373ffe6162210c42ce21e6eba294e547e3ad80219
@ -102,7 +99,7 @@ services:
ipv4_address: $LND_IP
dashboard:
container_name: dashboard
image: ghcr.io/runcitadel/dashboard:citadel-0.0.10@sha256:8920719b77a1db517e60742d72a4b63230f170d980d116f8e01974247e8da148
image: ghcr.io/runcitadel/dashboard:no-https@sha256:7fc5a5b70496240e6e48a381e8ac3c7978e7343285fda4951c00846580d6216d
restart: on-failure
stop_grace_period: 1m30s
networks:
@ -110,7 +107,7 @@ services:
ipv4_address: $DASHBOARD_IP
manager:
container_name: manager
image: ghcr.io/citadel-core/api:main@sha256:39f1caca276bb7b439613ce9e9a33a5a942143feb5ac6abbe079a9c85e19d56d
image: runcitadel/api:main@sha256:12d299d8850d830fa5abd0e64c8537dfcbaec662de18376b0d7b01fa59895132
depends_on:
- tor
restart: on-failure
@ -119,7 +116,7 @@ services:
volumes:
- ${PWD}/info.json:/info.json
- ${PWD}/db:/db
- ${PWD}/events:/events
- ${PWD}/karen.socket:/karen.socket
- ${PWD}/apps:/apps
- ${PWD}/lnd:/lnd:ro
- ${PWD}/statuses:/statuses
@ -134,6 +131,7 @@ services:
DEVICE_HOSTS: ${DEVICE_HOSTS:-"http://citadel.local"}
DEVICE_HOSTNAME: ${DEVICE_HOSTNAME:-""}
MIDDLEWARE_API_URL: http://$MIDDLEWARE_IP
MIDDLEWARE_API_PORT: 3000
SEED_FILE: /db/citadel-seed/seed
BITCOIN_HOST: $BITCOIN_IP
BITCOIN_P2P_PORT: $BITCOIN_P2P_PORT
@ -156,12 +154,14 @@ services:
I2P_USERNAME: i2pd
ELECTRUM_HOST: $APP_ELECTRUM_IP
ELECTRUM_PORT: 50001
KAREN_SOCKET: /karen.socket
IP_ADDR: $DEVICE_IP
networks:
default:
ipv4_address: $MANAGER_IP
middleware:
container_name: middleware
image: ghcr.io/runcitadel/middleware:main@sha256:fdb8b40a651cb4563c754c3f29d1826d32460100c9846d185e8609f0b357eec6
image: ghcr.io/runcitadel/middleware:main@sha256:cbd5fd2ab5afe420025c61e276d21c79a004d6148b8dfdd58649adb55907682b
depends_on:
- bitcoin
- lightning
@ -171,7 +171,7 @@ services:
- ${PWD}/lnd:/lnd
- jwt-public-key:/jwt-public-key
environment:
PORT: '3005'
PORT: '3000'
BITCOIN_HOST: $BITCOIN_IP
RPC_PORT: $BITCOIN_RPC_PORT
RPC_USER: $BITCOIN_RPC_USER
@ -217,7 +217,6 @@ services:
networks:
default:
ipv4_address: $I2P_IP
networks:
default:
name: citadel_main_network
@ -226,5 +225,7 @@ networks:
config:
- subnet: $NETWORK_IP/24
volumes:
jwt-public-key: null
jwt-private-key: null
jwt-public-key:
name: citadel-jwt-public-key
jwt-private-key:
name: citadel-jwt-private-key

View File

@ -21,6 +21,8 @@ EOF
wait
docker restart caddy &
"${CITADEL_ROOT}/scripts/app" start installed &
cat <<EOF > "$CITADEL_ROOT"/statuses/update-status.json
{"state": "installing", "progress": 60, "description": "Starting apps", "updateTo": "$RELEASE"}

View File

View File

@ -1,220 +0,0 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2022 Citadel and contributors
#
# SPDX-License-Identifier: GPL-3.0-or-later
try:
import crossplane
except ImportError:
print("Crossplane not found. Please run 'sudo pip3 install crossplane'")
exit(1)
import os
import argparse
import shutil
import json
def parse_dotenv(file_path):
envVars: dict = {}
with open(file_path, 'r') as file:
for line in file:
line = line.strip()
if line.startswith('#') or len(line) == 0:
continue
if '=' in line:
key, value = line.split('=', 1)
value = value.strip('"').strip("'")
envVars[key] = value
else:
print("Error: Invalid line in {}: {}".format(file_path, line))
print(
"Line should be in the format KEY=VALUE or KEY=\"VALUE\" or KEY='VALUE'")
exit(1)
return envVars
# Usage: add-https --service service_name --cert path_to_certificate --key path_to_key --domain domain_name
parser = argparse.ArgumentParser(
description='Create an HTTPS proxy for an app on Citadel')
parser.add_argument('--service', required=True,
help='The service to add HTTPS to')
parser.add_argument('--cert', required=True,
help='The path to the SSL certificate (.pem)')
parser.add_argument('--key', required=True, help='The path to the SSL key (.key)')
parser.add_argument('--domain', required=True, help='The domain name')
args = parser.parse_args()
domain = args.domain
service = args.service
cert = args.cert
key = args.key
node_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
nginx_config_file = os.path.join(node_root, 'nginx', 'nginx.conf')
registry_file = os.path.join(node_root, 'apps', 'registry.json')
with open(registry_file) as file:
registry = json.load(file)
port = None
for app in registry:
if app['name'] == service:
if "internalPort" in app:
port = app['internalPort']
break
original_config = crossplane.parse(nginx_config_file)
parsedConfig = original_config["config"][0]["parsed"]
ip_env_var = "APP_{}_WEB_IP".format(
service.upper().replace("-", "_")
)
ip_alt_env_var = "APP_{}_MAIN_IP".format(
service.upper().replace("-", "_")
)
port_env_var = "APP_{}_WEB_PORT".format(
service.upper().replace("-", "_")
)
port_alt_env_var = "APP_{}_MAIN_PORT".format(
service.upper().replace("-", "_")
)
env = parse_dotenv(os.path.join(node_root, '.env'))
ip=None
if ip_env_var in env:
ip = env[ip_env_var]
elif ip_alt_env_var in env:
ip = env[ip_alt_env_var]
else:
print("Error: No IP found for {}".format(service))
exit(1)
if port == None:
if port_env_var in env:
port = env[port_env_var]
elif port_alt_env_var in env:
port = env[port_alt_env_var]
else:
print("Error: No port found for {}".format(service))
exit(1)
if service == "btcpay-server":
port = 1234
if service == "lnme":
port = 1323
actual_url="http://{}:{}".format(ip, port)
# Get the first element of config where the directive property is 'http'
http_element = next(x for x in parsedConfig if x["directive"] == "http")
config = {
"directive": "server",
"args": [],
"block": [
{
"directive": "listen",
"args": ["443", "ssl", "http2"]
},
{
"directive": "server_name",
"args": [domain]
},
{
"directive": "ssl_certificate",
"args": [domain + ".pem"]
},
{
"directive": "ssl_certificate_key",
"args": [domain + ".key"]
},
{
"directive": "ssl_protocols",
"args": ["TLSv1", "TLSv1.1", "TLSv1.2"]
},
{
"directive": "ssl_ciphers",
"args": ["HIGH:!aNULL:!MD5"]
},
{
"directive": "location",
"args": ["/"],
"block": [
{
"directive": "proxy_pass",
"args": [actual_url]
},
{
"directive": "proxy_http_version",
"args": ["1.1"]
},
{
"directive": "proxy_set_header",
"args": ["Upgrade", "$http_upgrade"]
},
{
"directive": "proxy_set_header",
"args": ["Connection", "upgrade"]
},
{
"directive": "proxy_set_header",
"args": ["Host", "$host"]
},
{
"directive": "proxy_set_header",
"args": ["X-Real-IP", "$remote_addr"]
},
{
"directive": "proxy_set_header",
"args": ["X-Forwarded-For", "$remote_addr"]
},
{
"directive": "proxy_set_header",
"args": ["X-Forwarded-Proto", "$scheme"]
}
]
}
]
}
redirect_config = {
"directive": "server",
"args": [],
"block": [
{
"directive": "listen",
"args": ["433"]
},
{
"directive": "server_name",
"args": [domain]
},
{
"directive": "return",
"args": ["301", "https://$host$request_uri"]
},
]
}
# Now, copy the given certificate and key to the correct location
newCertLocation = os.path.join(node_root, 'nginx', domain + '.pem')
newKeyLocation = os.path.join(node_root, 'nginx', domain + '.key')
shutil.copy(cert, newCertLocation)
shutil.copy(key, newKeyLocation)
http_element["block"].append(config)
http_element["block"].append(redirect_config)
newConfig = crossplane.build(parsedConfig)
# Write newConfig to nginx_config_file
with open(nginx_config_file, 'w') as file:
file.write(newConfig)
print("Configuration successful!")
print("To increase security, we recommend not exposing our IP by using services like cloudflare.")
print("Also, please restart nginx using this command: sudo docker restart nginx")

92
scripts/configure vendored
View File

@ -4,16 +4,19 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
import sys
import os
from lib.rpcauth import get_data
import re
import subprocess
import json
import os
import re
import shutil
import yaml
import subprocess
import sys
from binascii import hexlify
from os import urandom
from time import sleep
import yaml
from lib.rpcauth import get_data
def generate_password(size):
"""Create size byte hex salt"""
@ -88,6 +91,7 @@ with open("./db/dependencies.yml", "r") as file:
# upon the user-supplied value of $NETWORK
# If the network is not specified, then use the mainnet
BITCOIN_NETWORK=os.environ.get('NETWORK') or 'mainnet'
DEVICE_IP=os.environ.get("DEVICE_IP")
# Check if network neither mainnet nor testnet nor regtest
if BITCOIN_NETWORK not in ['mainnet', 'testnet', 'signet', 'regtest']:
@ -137,8 +141,8 @@ def parse_dotenv(file_path):
############ Generate configuration variables ############
##########################################################
NGINX_PORT=os.environ.get('NGINX_PORT') or "80"
NGINX_SSL_PORT=os.environ.get('NGINX_SSL_PORT') or "443"
CADDY_PORT=os.environ.get('CADDY_PORT') or "80"
CADDY_HTTPS_PORT=os.environ.get('CADDY_PORT') or "443"
UPDATE_CHANNEL="stable"
if reconfiguring:
@ -155,14 +159,15 @@ if reconfiguring:
BITCOIN_RPC_USER=dotenv['BITCOIN_RPC_USER']
BITCOIN_RPC_PASS=dotenv['BITCOIN_RPC_PASS']
BITCOIN_RPC_AUTH=dotenv['BITCOIN_RPC_AUTH']
TOR_PASSWORD=dotenv['TOR_PASSWORD']
TOR_HASHED_PASSWORD=dotenv['TOR_HASHED_PASSWORD']
NGINX_PORT=dotenv['NGINX_PORT']
NGINX_SSL_PORT="443"
if 'NGINX_SSL_PORT' in dotenv:
NGINX_SSL_PORT=dotenv['NGINX_SSL_PORT']
if NGINX_SSL_PORT == "80" and NGINX_PORT == "80":
NGINX_SSL_PORT="443"
if 'NGINX_PORT' in dotenv:
CADDY_PORT=dotenv['NGINX_PORT']
if 'CADDY_PORT' in dotenv:
CADDY_PORT=dotenv['CADDY_PORT']
CADDY_HTTPS_PORT="443"
if 'CADDY_HTTPS_PORT' in dotenv:
CADDY_HTTPS_PORT=dotenv['CADDY_HTTPS_PORT']
if CADDY_HTTPS_PORT == "80" and CADDY_PORT == "80":
CADDY_HTTPS_PORT="443"
if 'UPDATE_CHANNEL' in dotenv and dotenv['UPDATE_CHANNEL'] != "main" and dotenv['UPDATE_CHANNEL'] != "migration":
UPDATE_CHANNEL=dotenv['UPDATE_CHANNEL']
if 'I2P_PASSWORD' in dotenv:
@ -176,7 +181,6 @@ else:
BITCOIN_RPC_DETAILS=get_data(BITCOIN_RPC_USER)
BITCOIN_RPC_AUTH=BITCOIN_RPC_DETAILS['auth']
BITCOIN_RPC_PASS=BITCOIN_RPC_DETAILS['password']
# Pull Tor image and generate Tor password
print("Generating Tor password\n")
os.system('docker pull --quiet {}'.format(dependencies["tor"]))
@ -255,19 +259,17 @@ if BITCOIN_NETWORK == "testnet":
# IP addresses for services
NETWORK_IP="10.21.21.0"
GATEWAY_IP="10.21.21.1"
NGINX_IP="10.21.21.2"
DASHBOARD_IP="10.21.21.3"
MANAGER_IP="10.21.21.4"
MIDDLEWARE_IP="10.21.21.5"
NEUTRINO_SWITCHER_IP="10.21.21.6"
DASHBOARD_NEW_IP="10.21.21.7"
BITCOIN_IP="10.21.21.8"
LND_IP="10.21.21.9"
TOR_PROXY_IP="10.21.21.11"
APPS_TOR_IP="10.21.21.12"
APPS_2_TOR_IP="10.21.21.13"
APPS_3_TOR_IP="10.21.21.14"
I2P_IP="10.21.21.15"
BITCOIN_IP="10.21.21.7"
LND_IP="10.21.21.8"
TOR_PROXY_IP="10.21.21.9"
APPS_TOR_IP="10.21.21.10"
APPS_2_TOR_IP="10.21.21.11"
APPS_3_TOR_IP="10.21.21.12"
I2P_IP="10.21.21.13"
# Ports
BITCOIN_RPC_PORT="8332"
@ -323,22 +325,7 @@ def replace_vars(file_path):
file_contents = file.read()
return re.sub(r'<(.*?)>', lambda m: get_var(convert_to_upper(m.group(1)), locals(), file_path), file_contents)
templates_to_build = {
"./templates/torrc-core-sample": "./tor/torrc-core",
"./templates/lnd-sample.conf": "./lnd/lnd.conf",
"./templates/bitcoin-sample.conf": "./bitcoin/bitcoin.conf",
"./templates/.env-sample": "./.env",
"./templates/nginx-sample.conf": "./nginx/nginx.conf",
"./templates/i2p-sample.conf": "./i2p/i2pd.conf",
"./templates/i2p-tunnels-sample.conf": "./i2p/tunnels.conf"
}
print("Generating configuration files...")
# Loop through templates_to_build and build them
for template_path, output_path in templates_to_build.items():
if output_path == "./nginx/nginx.conf" and os.path.isfile(output_path):
continue
def build_template(template_path, output_path):
data = replace_vars(template_path)
# If output path is a list, then it is a list of output paths
if isinstance(output_path, list):
@ -355,9 +342,15 @@ for template_path, output_path in templates_to_build.items():
with open(output_path, 'w') as file:
file.write(data)
print("Generated configuration files\n")
print("Generating configuration files...")
build_template("./templates/torrc-core-sample", "./tor/torrc-core")
build_template("./templates/bitcoin-sample.conf", "./bitcoin/bitcoin.conf")
build_template("./templates/i2p-sample.conf", "./i2p/i2pd.conf")
build_template("./templates/i2p-tunnels-sample.conf", "./i2p/tunnels.conf")
build_template("./templates/lnd-sample.conf", "./lnd/lnd.conf")
build_template("./templates/.env-sample", "./.env")
print("Checking if Docker Compose is installed...")
print("Ensuring Docker Compose is up to date...")
download_docker_compose()
print("Updating core services...")
@ -377,14 +370,21 @@ try:
except: pass
if not reconfiguring:
print("Updating apps...\n")
print("Downloading apps...\n")
os.system('./scripts/app update')
else:
print("Updating apps...\n")
print("Generating app configuration...\n")
os.system('./scripts/app generate')
# Touch status_dir/configured
with open(status_dir+'/configured', 'w') as file:
file.write('')
print("Configuring permissions...\n")
try:
os.system('chown -R 1000:1000 {}'.format(CITADEL_ROOT))
except: pass
print("Configuration successful\n")
print("You can now start Citadel by running:")
print(" sudo ./scripts/start")

View File

@ -6,7 +6,7 @@ statuses
tor/*
logs/*
app-data/*
nginx/*
caddy/*
services/installed.yml
apps/*
i2p/*

View File

@ -8,3 +8,4 @@ apps/docker-compose.common.yml
services/bitcoin/*
services/lightning/*
db/dependencies.yml
apps/stores.yml

View File

@ -120,8 +120,6 @@ cat <<EOF > "$CITADEL_ROOT"/statuses/update-status.json
{"state": "installing", "progress": 80, "description": "Starting new containers", "updateTo": "$RELEASE"}
EOF
cd "$CITADEL_ROOT"
# Delete old nginx.conf
rm -rf nginx/nginx.conf
./scripts/start || true

View File

@ -9,7 +9,7 @@ How over-the-air updates work on Citadel.
## Execution Flow
1. New developments across the any/entire fleet of Citadel's services (bitcoind, lnd, dashboard, middleware, etc) are made, which maintain their own independent version-control and release-schedule. Subsequently, their new docker images are built, tagged and pushed to Docker Hub.
1. New developments across the any/entire fleet of Citadel's services (bitcoind, dashboard, manager, etc) are made, which maintain their own independent version-control and release-schedule. Subsequently, their new docker images are built, tagged and pushed to Docker Hub.
2. The newly built and tagged images are updated in the main repository's (i.e. this repo) [`docker-compose.yml`](https://github.com/runcitadel/core/blob/main/docker-compose.yml) file.

View File

@ -5,13 +5,12 @@
# Citadel Core
DEVICE_HOSTNAME=<device-hostname>.local
DEVICE_IP=<device-ip>
NETWORK_IP=<network-ip>
GATEWAY_IP=<gateway-ip>
NGINX_IP=<nginx-ip>
NGINX_PORT=<nginx-port>
NGINX_SSL_PORT=<nginx-ssl-port>
CADDY_PORT=<caddy-port>
CADDY_HTTPS_PORT=<caddy-https-port>
DASHBOARD_IP=<dashboard-ip>
DASHBOARD_NEW_IP=<dashboard-new-ip>
MANAGER_IP=<manager-ip>
MIDDLEWARE_IP=<middleware-ip>
NEUTRINO_SWITCHER_IP=<neutrino-switcher-ip>

75
templates/Caddyfile.jinja Normal file
View File

@ -0,0 +1,75 @@
{% if https_options and https_options.agreed_lets_encrypt_tos and https_options.email %}
{
acme_ca https://acme-v02.api.letsencrypt.org/directory
email {{ https_options.email }}
}
{% endif %}
:{{CADDY_PORT}} {
route /api/* {
uri strip_prefix /api
reverse_proxy {{MIDDLEWARE_IP}}:3000
}
route /api-v2/* {
uri strip_prefix /api-v2
reverse_proxy {{MANAGER_IP}}:3000
}
reverse_proxy {{DASHBOARD_IP}}:3004
}
{% if https_options and https_options.agreed_lets_encrypt_tos and https_options.email and https_options.app_domains and https_options.app_domains.dashboard %}
{{https_options.app_domains.dashboard}} {
{% if https_options.user and https_options.user.username and https_options.user.password and https_options.app_domains.dashboard is ending_with(".runningcitadel.com") %}
tls {
dns runningcitadel {{ https_options.user.username }} {{ https_options.user.password }}
}
{% endif %}
route /api/* {
uri strip_prefix /api
reverse_proxy {{MIDDLEWARE_IP}}:3000
}
route /api-v2/* {
uri strip_prefix /api-v2
reverse_proxy {{MANAGER_IP}}:3000
}
reverse_proxy {{DASHBOARD_IP}}:3004
}
{% endif %}
{% for app_id, entries in caddy_entries %}
{% for entry in entries %}
:{{entry.public_port}} {
{% set container_ip_entry = "APP_" ~ app_id ~ "_" ~ entry.container_name ~ "_IP" | upper | replace(from="-", to="_") %}
reverse_proxy {{ ip_map[container_ip_entry] }}:{{ entry.internal_port }}
}
{% endfor %}
{% endfor %}
{% if https_options and https_options.agreed_lets_encrypt_tos and https_options.email and https_options.app_domains %}
{% for app_id, domain in https_options.app_domains %}
{% if app_id != "dashboard" %}
{% for entry in caddy_entries[app_id] %}
{% if entry.is_primary %}
{{domain}} {
{% set container_ip_entry = "APP_" ~ app_id ~ "-" ~ entry.container_name ~ "_IP" | upper | replace(from="-", to="_") %}
reverse_proxy {{ ip_map[container_ip_entry] }}:{{ entry.internal_port }}
{% if https_options.user and https_options.user.username and https_options.user.password and domain is ending_with(".runningcitadel.com") %}
tls {
dns runningcitadel {{ https_options.user.username }} {{ https_options.user.password }}
}
{% endif %}
}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}

View File

@ -1,5 +1,5 @@
[dashboard]
type = http
host = <nginx-ip>
host = host.docker.internal
port = 80
keys = citadel-dashboard.dat

View File

@ -4,13 +4,12 @@
# Bind only to "<tor-proxy-ip>" which is the tor IP within the container
SocksPort <tor-proxy-ip>:<tor-proxy-port>
ControlPort <tor-proxy-ip>:<tor-control-port>
# Citadel Core Services
# Dashboard Hidden Service
HiddenServiceDir /var/lib/tor/web
HiddenServicePort 80 <nginx-ip>:80
HiddenServicePort 80 host.docker.internal:80
# Bitcoin Core P2P Hidden Service
HiddenServiceDir /var/lib/tor/bitcoin-p2p
@ -20,13 +19,3 @@ HiddenServicePort <bitcoin-p2p-port> <bitcoin-ip>:<bitcoin-p2p-port>
HiddenServiceDir /var/lib/tor/bitcoin-rpc
HiddenServicePort <bitcoin-rpc-port> <bitcoin-ip>:<bitcoin-rpc-port>
# LND REST Hidden Service
HiddenServiceDir /var/lib/tor/lnd-rest
HiddenServicePort <lnd-rest-port> <lnd-ip>:<lnd-rest-port>
# LND gRPC Hidden Service
HiddenServiceDir /var/lib/tor/lnd-grpc
HiddenServicePort <lnd-grpc-port> <lnd-ip>:<lnd-grpc-port>
HashedControlPassword <tor-hashed-password>