chore(do/1-click): sunset DigitalOcean 1-click app (#2074)
This commit is contained in:
Родитель
2e59d231b5
Коммит
08d1bffdf6
|
@ -39,8 +39,9 @@ What is Speckle? Check our [![YouTube Video Views](https://img.shields.io/youtub
|
|||
|
||||
Give Speckle a try in no time by:
|
||||
|
||||
- [![speckle](https://img.shields.io/badge/https://-app.speckle.systems-0069ff?style=flat-square&logo=hackthebox&logoColor=white)](https://app.speckle.systems) ⇒ creating an account
|
||||
- [![create a droplet](https://img.shields.io/badge/Create%20a%20Droplet-0069ff?style=flat-square&logo=digitalocean&logoColor=white)](https://marketplace.digitalocean.com/apps/speckle-server?refcode=947a2b5d7dc1) ⇒ deploying an instance in 1 click
|
||||
- [![app.speckle.systems](https://img.shields.io/badge/https://-app.speckle.systems-0069ff?style=flat-square&logo=hackthebox&logoColor=white)](https://app.speckle.systems) ⇒ Create an account at app.speckle.systems
|
||||
- [![Deploy on your own infrastructure with docker compose](https://img.shields.io/badge/https://-speckle.guide-0069ff?style=flat-square&logo=hackthebox&logoColor=white)](<[https://](https://speckle.guide/dev/server-manualsetup.html)>) ⇒ Deploy on your own infrastructure with Docker Compose
|
||||
- [![Deploy on your own infrastructure with docker compose](https://img.shields.io/badge/https://-speckle.guide-0069ff?style=flat-square&logo=hackthebox&logoColor=white)](<[https://](https://speckle.guide/dev/server-setup-k8s.html)>) ⇒ Deploy on your own infrastructure with Kubernetes
|
||||
|
||||
## Resources
|
||||
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "* Getting latest version of SpeckleServer Setup files..."
|
||||
|
||||
mkdir -p /opt/speckle-server
|
||||
cd /opt/speckle-server || exit 1
|
||||
|
||||
wget https://raw.githubusercontent.com/specklesystems/speckle-server/main/utils/1click_image_scripts/setup.py -O setup.py
|
||||
wget https://raw.githubusercontent.com/specklesystems/speckle-server/main/utils/1click_image_scripts/template-nginx-site.conf -O template-nginx-site.conf
|
||||
wget https://raw.githubusercontent.com/specklesystems/speckle-server/main/utils/1click_image_scripts/template-docker-compose.yml -O template-docker-compose.yml
|
||||
|
||||
docker image rm {speckle/speckle-preview-service:2,speckle/speckle-webhook-service:2,speckle/speckle-server:2,speckle/speckle-frontend:2} || true
|
||||
chmod +x setup.py
|
||||
|
||||
echo "* Getting the docker images for the latest SpeckleServer release..."
|
||||
docker compose -f template-docker-compose.yml pull
|
|
@ -1,14 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import socket
|
||||
import subprocess
|
||||
import secrets
|
||||
import ruamel.yaml # this module preserves yaml comments and whitespaces
|
||||
from ruamel.yaml.scalarstring import DoubleQuotedScalarString
|
||||
|
||||
FILE_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
LOGO_STR = """
|
||||
_____ _ _ _____
|
||||
/ ___| | | | | / ___|
|
||||
|
@ -21,202 +12,22 @@ LOGO_STR = """
|
|||
"""
|
||||
|
||||
|
||||
def get_local_ip():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.connect(("8.8.8.8", 80))
|
||||
ip = s.getsockname()[0]
|
||||
s.close()
|
||||
if not ip:
|
||||
print("Error: Can't get local IP address")
|
||||
exit(1)
|
||||
return ip
|
||||
|
||||
|
||||
def read_domain(ip):
|
||||
print("\nYou can set up a domain name for this Speckle server.")
|
||||
print(
|
||||
"Important: To use a domain name, you must first configure it to point to this VM address (so we can issue the SSL certificate)"
|
||||
)
|
||||
print(f"VM address: {ip}")
|
||||
while True:
|
||||
domain = input("Domain name (leave blank to use the IP address): ").strip()
|
||||
if not domain:
|
||||
return None
|
||||
try:
|
||||
domain_ip = socket.gethostbyname(domain.strip())
|
||||
except Exception as ex:
|
||||
print(f"Error: Domain '{domain}' cannot be resolved: {str(ex)}")
|
||||
continue
|
||||
|
||||
if domain_ip != ip:
|
||||
print(f"Error: Domain '{domain}' points to {domain_ip} instead of {ip}")
|
||||
continue
|
||||
|
||||
return domain
|
||||
|
||||
|
||||
def read_email_settings(domain):
|
||||
print(
|
||||
"\nYou should configure an email provider to allow the Speckle Server to send emails."
|
||||
)
|
||||
print(
|
||||
"Supported vendors: Any email provider that can provide SMTP connection details (mailjet, mailgun, etc)."
|
||||
)
|
||||
print(
|
||||
"Important: If you don't configure email details, some features that require sending emails will not work, nevertheless the server should be functional."
|
||||
)
|
||||
while True:
|
||||
enable_email = False
|
||||
while True:
|
||||
enable_email = input("Enable emails? [Y/n]: ").strip().lower()
|
||||
if enable_email in ["n", "no"]:
|
||||
enable_email = False
|
||||
break
|
||||
elif enable_email in ["", "y", "yes"]:
|
||||
enable_email = True
|
||||
break
|
||||
else:
|
||||
print("Unrecognized option")
|
||||
continue
|
||||
|
||||
if not enable_email:
|
||||
return None
|
||||
|
||||
print("Enter your SMTP connection details offered by your email provider")
|
||||
smtp_host = input("SMTP server / host: ").strip()
|
||||
smtp_port = input("SMTP port: ").strip()
|
||||
try:
|
||||
int(smtp_port)
|
||||
except Exception:
|
||||
print("Error: SMTP port must be a number. Retrying...")
|
||||
continue
|
||||
smtp_user = input("SMTP Username: ").strip()
|
||||
smtp_pass = input("SMTP Password: ").strip()
|
||||
|
||||
if domain:
|
||||
default_from_email = "no-reply@" + domain
|
||||
else:
|
||||
default_from_email = ""
|
||||
email_from = input(f"Email address to send email as [{default_from_email}]: ")
|
||||
if not email_from.strip():
|
||||
email_from = default_from_email
|
||||
|
||||
if (
|
||||
not smtp_host
|
||||
or not smtp_port
|
||||
or not smtp_user
|
||||
or not smtp_pass
|
||||
or not email_from
|
||||
):
|
||||
print("Error: One or more fields were empty. Retrying...")
|
||||
continue
|
||||
|
||||
return {
|
||||
"host": smtp_host,
|
||||
"port": smtp_port,
|
||||
"user": smtp_user,
|
||||
"pass": smtp_pass,
|
||||
"from": email_from,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
print(LOGO_STR)
|
||||
ip = get_local_ip()
|
||||
|
||||
###
|
||||
### Read user input
|
||||
#########
|
||||
domain = read_domain(ip)
|
||||
if domain:
|
||||
canonical_url = f"https://{domain}"
|
||||
else:
|
||||
canonical_url = f"http://{ip}"
|
||||
|
||||
email = read_email_settings(domain)
|
||||
|
||||
###
|
||||
### Create docker-compose.yml from the template
|
||||
#########
|
||||
print("\nConfiguring docker containers...")
|
||||
|
||||
yaml = ruamel.yaml.YAML()
|
||||
yaml.preserve_quotes = True
|
||||
with open(os.path.join(FILE_PATH, "template-docker-compose.yml"), "r") as f:
|
||||
yml_doc = yaml.load(f)
|
||||
env = yml_doc["services"]["speckle-server"]["environment"]
|
||||
env["CANONICAL_URL"] = DoubleQuotedScalarString(canonical_url)
|
||||
env["FRONTEND_ORIGIN"] = DoubleQuotedScalarString(canonical_url)
|
||||
env["SESSION_SECRET"] = DoubleQuotedScalarString(secrets.token_hex(32))
|
||||
if email:
|
||||
env["EMAIL"] = DoubleQuotedScalarString("true")
|
||||
env["EMAIL_HOST"] = DoubleQuotedScalarString(email["host"])
|
||||
env["EMAIL_PORT"] = DoubleQuotedScalarString(email["port"])
|
||||
env["EMAIL_USERNAME"] = DoubleQuotedScalarString(email["user"])
|
||||
env["EMAIL_PASSWORD"] = DoubleQuotedScalarString(email["pass"])
|
||||
env["EMAIL_FROM"] = DoubleQuotedScalarString(email["from"])
|
||||
else:
|
||||
env["EMAIL"] = DoubleQuotedScalarString("false")
|
||||
|
||||
fe2env = yml_doc["services"]["speckle-frontend-2"]["environment"]
|
||||
fe2env["NUXT_PUBLIC_SERVER_NAME"] = DoubleQuotedScalarString(canonical_url)
|
||||
fe2env["NUXT_PUBLIC_API_ORIGIN"] = DoubleQuotedScalarString(canonical_url)
|
||||
fe2env["NUXT_PUBLIC_BASE_URL"] = DoubleQuotedScalarString(canonical_url)
|
||||
|
||||
with open(os.path.join(FILE_PATH, "docker-compose.yml"), "w") as f:
|
||||
f.write("# This file was generated by SpeckleServer setup.\n")
|
||||
f.write("# If the setup is re-run, this file will be overwritten.\n\n")
|
||||
yaml.dump(yml_doc, f)
|
||||
|
||||
###
|
||||
### Run the new docker compose file (will update containers if already running)
|
||||
#########
|
||||
subprocess.run(
|
||||
["bash", "-c", f'cd "{FILE_PATH}"; docker compose up -d'], check=True
|
||||
)
|
||||
|
||||
###
|
||||
### Update nginx config and restart nginx
|
||||
#########
|
||||
print("\nConfiguring local nginx...")
|
||||
|
||||
nginx_conf_str = "# This file is managed by SpeckleServer setup script.\n"
|
||||
nginx_conf_str += (
|
||||
"# Any modifications will be removed when the setup script is re-executed\n\n"
|
||||
)
|
||||
with open(os.path.join(FILE_PATH, "template-nginx-site.conf"), "r") as f:
|
||||
nginx_conf_str += f.read()
|
||||
if domain:
|
||||
nginx_conf_str = nginx_conf_str.replace("TODO_REPLACE_WITH_SERVER_NAME", domain)
|
||||
else:
|
||||
nginx_conf_str = nginx_conf_str.replace("TODO_REPLACE_WITH_SERVER_NAME", "_")
|
||||
with open("/etc/nginx/sites-available/speckle-server", "w") as f:
|
||||
f.write(nginx_conf_str)
|
||||
subprocess.run(["nginx", "-s", "reload"], check=True)
|
||||
|
||||
###
|
||||
### Run letsencrypt on new config
|
||||
#########
|
||||
if domain:
|
||||
print("\n***")
|
||||
print(
|
||||
"*** Will now run LetsEncrypt utility to generate https certificate. Please answer any questions that are presented"
|
||||
"\nAs of March 2024, Speckle server DigitalOcean 1-click setup script is no longer supported."
|
||||
)
|
||||
print(
|
||||
"*** We highly recommend setting a good email address so that you are notified if there is any action needed to renew certificates"
|
||||
)
|
||||
print("***")
|
||||
subprocess.run(["certbot", "--nginx", "-d", domain])
|
||||
|
||||
print("\nConfiguration complete!")
|
||||
print("You can access your speckle server at: " + canonical_url)
|
||||
print(LOGO_STR)
|
||||
print("\nOne more thing and you are ready to roll:")
|
||||
print(
|
||||
f" - Go to {canonical_url} in your browser and create an account. The first user to register will be granted administrator rights."
|
||||
"\nPlease use the official Speckle Server installation guide to install Speckle Server on your own infrastructure."
|
||||
)
|
||||
print(
|
||||
" - Fill in information about your server under your profile page (in the lower left corner)."
|
||||
"\nThis could be on a DigitalOcean Droplet that you have created yourself using an Ubuntu image."
|
||||
)
|
||||
print(
|
||||
"\nOur documentation can be found at https://speckle.guide/dev/server-manualsetup.html"
|
||||
)
|
||||
print(
|
||||
"\nIf you require to view previous versions of the 1-click setup script, please review the history of the speckle-server repository on GitHub."
|
||||
)
|
||||
print("\nHappy Speckling!")
|
||||
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
version: '2.3'
|
||||
services:
|
||||
####
|
||||
# Speckle Server dependencies
|
||||
#######
|
||||
postgres:
|
||||
image: 'postgres:14.5-alpine'
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_DB: speckle
|
||||
POSTGRES_USER: speckle
|
||||
POSTGRES_PASSWORD: speckle
|
||||
volumes:
|
||||
- ./postgres-data:/var/lib/postgresql/data/
|
||||
ports:
|
||||
- '127.0.0.1:5432:5432'
|
||||
|
||||
redis:
|
||||
image: 'redis:7.0-alpine'
|
||||
restart: always
|
||||
volumes:
|
||||
- ./redis-data:/data
|
||||
ports:
|
||||
- '127.0.0.1:6379:6379'
|
||||
|
||||
minio:
|
||||
image: 'minio/minio'
|
||||
command: server /data --console-address ":9001"
|
||||
restart: always
|
||||
volumes:
|
||||
- ./minio-data:/data
|
||||
ports:
|
||||
- '127.0.0.1:9000:9000'
|
||||
- '127.0.0.1:9001:9001'
|
||||
|
||||
####
|
||||
# Speckle Server
|
||||
#######
|
||||
speckle-frontend-2:
|
||||
image: speckle/speckle-frontend-2:2
|
||||
restart: always
|
||||
ports:
|
||||
- '127.0.0.1:8080:8080'
|
||||
environment:
|
||||
NUXT_PUBLIC_SERVER_NAME: 'TODO: change' # e.g. 'my-speckle-server'
|
||||
NUXT_PUBLIC_API_ORIGIN: 'TODO: change' # e.g. 'http://127.0.0.1'
|
||||
NUXT_PUBLIC_BASE_URL: 'TODO: change' # e.g. 'http://127.0.0.1'
|
||||
NUXT_PUBLIC_BACKEND_API_ORIGIN: 'http://speckle-server:3000'
|
||||
NUXT_PUBLIC_LOG_LEVEL: 'warn'
|
||||
NUXT_REDIS_URL: 'redis://redis'
|
||||
|
||||
speckle-server:
|
||||
image: speckle/speckle-server:2
|
||||
restart: always
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
- node
|
||||
- -e
|
||||
- "try { require('node:http').request({headers: {'Content-Type': 'application/json'}, port:3000, hostname:'127.0.0.1', path:'/liveness', method: 'GET', timeout: 2000 }, (res) => { body = ''; res.on('data', (chunk) => {body += chunk;}); res.on('end', () => {process.exit(res.statusCode != 200 || body.toLowerCase().includes('error'));}); }).end(); } catch { process.exit(1); }"
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 90s
|
||||
ports:
|
||||
- '127.0.0.1:3000:3000'
|
||||
environment:
|
||||
CANONICAL_URL: 'TODO: change'
|
||||
SESSION_SECRET: 'TODO: change'
|
||||
|
||||
STRATEGY_LOCAL: 'true'
|
||||
LOG_LEVEL: 'info'
|
||||
|
||||
POSTGRES_URL: 'postgres'
|
||||
POSTGRES_USER: 'speckle'
|
||||
POSTGRES_PASSWORD: 'speckle'
|
||||
POSTGRES_DB: 'speckle'
|
||||
|
||||
REDIS_URL: 'redis://redis'
|
||||
WAIT_HOSTS: 'postgres:5432, redis:6379, minio:9000'
|
||||
|
||||
EMAIL: 'false'
|
||||
EMAIL_HOST: 'TODO'
|
||||
EMAIL_PORT: 'TODO'
|
||||
EMAIL_USERNAME: 'TODO'
|
||||
EMAIL_PASSWORD: 'TODO'
|
||||
EMAIL_FROM: 'TODO'
|
||||
|
||||
EMAIL_SECURE: 'false'
|
||||
|
||||
S3_ENDPOINT: 'http://minio:9000'
|
||||
S3_ACCESS_KEY: 'minioadmin'
|
||||
S3_SECRET_KEY: 'minioadmin'
|
||||
S3_BUCKET: 'speckle-server'
|
||||
S3_CREATE_BUCKET: 'true'
|
||||
S3_REGION: '' # optional, defaults to 'us-east-1'
|
||||
|
||||
FILE_SIZE_LIMIT_MB: 100
|
||||
|
||||
USE_FRONTEND_2: 'true'
|
||||
FRONTEND_ORIGIN: 'TODO: change'
|
||||
|
||||
speckle-preview-service:
|
||||
image: speckle/speckle-preview-service:2
|
||||
restart: always
|
||||
mem_limit: '1000m'
|
||||
memswap_limit: '1000m'
|
||||
|
||||
environment:
|
||||
LOG_LEVEL: 'info'
|
||||
PG_CONNECTION_STRING: 'postgres://speckle:speckle@postgres/speckle'
|
||||
WAIT_HOSTS: 'postgres:5432'
|
||||
|
||||
speckle-webhook-service:
|
||||
image: speckle/speckle-webhook-service:2
|
||||
restart: always
|
||||
environment:
|
||||
LOG_LEVEL: 'info'
|
||||
PG_CONNECTION_STRING: 'postgres://speckle:speckle@postgres/speckle'
|
||||
WAIT_HOSTS: 'postgres:5432'
|
||||
|
||||
fileimport-service:
|
||||
image: speckle/speckle-fileimport-service:2
|
||||
restart: always
|
||||
environment:
|
||||
LOG_LEVEL: 'info'
|
||||
PG_CONNECTION_STRING: 'postgres://speckle:speckle@postgres/speckle'
|
||||
WAIT_HOSTS: 'postgres:5432'
|
||||
SPECKLE_SERVER_URL: 'http://speckle-server:3000'
|
|
@ -1,35 +0,0 @@
|
|||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
server_name TODO_REPLACE_WITH_SERVER_NAME;
|
||||
|
||||
client_max_body_size 100m;
|
||||
|
||||
location / {
|
||||
client_max_body_size 100m;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_pass http://localhost:8080;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
location ~* ^/(graphql|explorer|(auth/.*)|(objects/.*)|(preview/.*)|(api/.*)|(static/.*)) {
|
||||
client_max_body_size 100m;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_pass http://localhost:3000;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче