Steve/EV Dashboard/nginx 도커파일 및 설정파일 추가

This commit is contained in:
byun
2026-05-26 21:10:16 +09:00
parent 8617642fae
commit 607e4d758b
9 changed files with 402 additions and 0 deletions

35
ev-charging-backend/.env Normal file
View File

@@ -0,0 +1,35 @@
# ── 데이터베이스 ──
POSTGRES_DB=ev_charging
POSTGRES_USER=evuser
POSTGRES_PASSWORD=evpass1234
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
# ── Redis ──
REDIS_HOST=redis
REDIS_PORT=6379
# ── Steve OCPP 서버 ──
STEVE_BASE_URL=https://s1.byunc.com/steve
STEVE_API_USER=admin
STEVE_API_PASSWORD=changeme
# ── 토스페이먼츠 ──
TOSS_CLIENT_KEY=test_ck_Poxy1XQL8RYmzR9JgL5lr7nO5Wml
TOSS_SECRET_KEY=test_sk_ZLKGPx4M3M90lvAvzx1n3BaWypv1
#TOSS_CLIENT_KEY=test_ck_xxxxxxxxxx
#TOSS_SECRET_KEY=test_sk_xxxxxxxxxx
# ── 요금 설정 (원/kWh) ──
ELECTRICITY_RATE=120
SERVICE_MARGIN=50
# ── JWT ──
JWT_SECRET=your-super-secret-key-change-this
JWT_ALGORITHM=HS256
JWT_EXPIRE_MINUTES=1440
# ── 서버 ──
SERVER_HOST=0.0.0.0
SERVER_PORT=8000
DEBUG=true

View File

@@ -0,0 +1,15 @@
FROM python:3.11-slim
WORKDIR /code
# 시스템 패키지
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libpq-dev && \
rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY ./app /code/app
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

View File

@@ -0,0 +1,10 @@
FROM python:3.11-slim
WORKDIR /code
RUN pip install --no-cache-dir websockets aiohttp
COPY entrypoint-proxy.sh /code/
RUN chmod +x /code/entrypoint-proxy.sh
CMD ["/code/entrypoint-proxy.sh"]

View File

@@ -0,0 +1,84 @@
services:
# ── FastAPI 백엔드 ──
api:
build: .
container_name: ev-api
restart: unless-stopped
ports:
- "8000:8000"
env_file:
- .env
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- ./app:/code/app
- ./dashboard.html:/code/dashboard.html:ro
- ./simulator.html:/code/simulator.html:ro
networks:
- ev-net
# ── OCPP 프록시 서버 ──
proxy:
build:
context: .
dockerfile: Dockerfile.proxy
container_name: ev-proxy
restart: unless-stopped
ports:
- "9002:9002"
- "9003:9003"
volumes:
- ./ocpp_proxy_server.py:/code/ocpp_proxy_server.py:ro
- ./proxy_control.html:/code/proxy_control.html:ro
- proxy_logs:/code/ocpp_logs
- proxy_config:/code/config
networks:
- ev-net
# ── PostgreSQL ──
postgres:
image: postgres:16-alpine
container_name: ev-postgres
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB:-ev_charging}
POSTGRES_USER: ${POSTGRES_USER:-evuser}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-evpass1234}
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-evuser}"]
interval: 5s
timeout: 3s
retries: 5
networks:
- ev-net
# ── Redis ──
redis:
image: redis:7-alpine
container_name: ev-redis
restart: unless-stopped
ports:
- "6375:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
networks:
- ev-net
volumes:
pgdata:
proxy_logs:
proxy_config:
networks:
ev-net:
driver: bridge

89
nginx/s1.byunc.com.conf Normal file
View File

@@ -0,0 +1,89 @@
server {
#listen [::]:80;
#root /var/www/html/mysite.com;
index index.php index.html index.htm;
server_name s1.byunc.com;
#error_log /var/log/nginx/mysite.com_error.log;
#access_log /var/log/nginx/mysite.com_access.log;
client_max_body_size 16G;
location = / {
return 302 /steve/;
}
location /steve {
proxy_pass http://192.168.0.126:8180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# ── FastAPI 대시보드 + API ──
location = /dashboard {
proxy_pass http://192.168.0.126:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api/ {
proxy_pass http://192.168.0.126:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /health {
proxy_pass http://192.168.0.126:8000;
}
# WebSocket 전용 설정 (핵심)
location /steve/websocket {
proxy_pass http://192.168.0.126:8180;
# WebSocket 업그레이드 헤더
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
# WebSocket 타임아웃 (충전 중 끊기지 않게)
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 86400s;
}
location / {
proxy_pass http://192.168.0.126:8180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_buffering off;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_connect_timeout 86400s;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/s1.byunc.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/s1.byunc.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = s1.byunc.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name s1.byunc.com;
listen 80;
return 404; # managed by Certbot
}

25
steve/Dockerfile Normal file
View File

@@ -0,0 +1,25 @@
FROM eclipse-temurin:21-jdk
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
MAINTAINER Ling Li
# Download and install dockerize.
# Needed so the web container will wait for MariaDB to start.
ENV DOCKERIZE_VERSION v0.19.0
RUN curl -sfL https://github.com/powerman/dockerize/releases/download/"$DOCKERIZE_VERSION"/dockerize-`uname -s`-`uname -m` | install /dev/stdin /usr/local/bin/dockerize
EXPOSE 8180
EXPOSE 8443
WORKDIR /code
VOLUME ["/code"]
# Copy the application's code
COPY . /code
# Wait for the db to startup(via dockerize), then
# Build and run steve, requires a db to be available on port 3306
CMD dockerize -wait tcp://mariadb:3306 -timeout 60s && \
./mvnw clean package -Pdocker,mariadb -Djdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2" && \
java -XX:MaxRAMPercentage=85 -jar target/steve.war

View File

@@ -0,0 +1,47 @@
/*
* SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve
* Copyright (C) 2013-2026 SteVe Community Team
* All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.rwth.idsg.steve.config;
import org.eclipse.jetty.http.HttpCompliance;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.ServerConnector;
import org.springframework.boot.jetty.JettyServerCustomizer;
import org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JettyConfiguration {
@Bean
public WebServerFactoryCustomizer<JettyServletWebServerFactory> jettyHttpComplianceCustomizer() {
return factory -> factory.addServerCustomizers((JettyServerCustomizer) server -> {
for (var connector : server.getConnectors()) {
if (connector instanceof ServerConnector serverConnector) {
for (var cf : serverConnector.getConnectionFactories()) {
if (cf instanceof HttpConnectionFactory httpCF) {
httpCF.getHttpConfiguration().setHttpCompliance(HttpCompliance.RFC7230_LEGACY);
}
}
}
}
});
}
}

View File

@@ -0,0 +1,66 @@
# Just to be backwards compatible with previous versions, this is set to "steve",
# since there might be already configured chargepoints expecting the older path.
# Otherwise, might as well be changed to something else or be left empty.
#
context.path = steve
# Database configuration
#
db.ip = mariadb
db.port = 3306
db.schema = stevedb
db.user = steve
db.password = changeme
# Credentials for Web interface access
#
auth.user = admin
auth.password = 1234
# The header key and value for Web API access using API key authorization.
# Both must be set for Web APIs to be enabled. Otherwise, we will block all calls.
#
webapi.key = STEVE-API-KEY
webapi.value =
# Jetty configuration
#
server.host = 0.0.0.0
server.gzip.enabled = false
# Jetty HTTP configuration
#
http.enabled = true
http.port = 8180
# Jetty HTTPS configuration
#
https.enabled = false
https.port = 8443
keystore.path =
keystore.password =
# When the WebSocket/Json charge point opens more than one WebSocket connection,
# we need a mechanism/strategy to select one of them for outgoing requests.
# For allowed values see de.rwth.idsg.steve.ocpp.ws.custom.WsSessionSelectStrategyEnum.
#
ws.session.select.strategy = ALWAYS_LAST
# if BootNotification messages arrive (SOAP) or WebSocket connection attempts are made (JSON) from unknown charging
# stations, we reject these charging stations, because stations with these chargeBoxIds were NOT inserted into database
# beforehand. by setting this property to true, this behaviour can be modified to automatically insert unknown
# stations into database and accept their requests.
#
# CAUTION: setting this property to true is very dangerous, because we will accept EVERY BootNotification or WebSocket
# connection attempt from ANY sender as long as the sender knows the URL and sends a valid message.
#
auto.register.unknown.stations = false
# if this field is set, it will take precedence over the default regex we are using in
# de.rwth.idsg.steve.web.validation.ChargeBoxIdValidator.REGEX to validate the format of the chargeBoxId values
#
charge-box-id.validation.regex =
### DO NOT MODIFY ###
db.sql.logging = false
profile = prod

31
steve/docker-compose.yml Normal file
View File

@@ -0,0 +1,31 @@
version: "3.0"
volumes:
db-data:
external: false
services:
db:
image: mariadb:10.11.16
restart: unless-stopped
ports:
- 3307:3306
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: stevedb
MYSQL_USER: steve
MYSQL_PASSWORD: changeme
app:
restart: unless-stopped
build: .
links:
- "db:mariadb"
volumes:
- .:/code
ports:
- "8180:8180"
- "8445:8443"
depends_on:
- db