xxx.xxx.com 構築手順まとめ(Ubuntu / Nginx同居 / ABR + Flask)肝心のソースコードは無し

xxx.xxx.com 構築手順まとめ 肝心のソースコードは無し

Ubuntu / Nginx同居 / HTTPS(LE) / ABR(abr-geocoder) + Flask(Gunicorn) / GSI reverse(座標→住所)

1. 目的と提供API

公開ドメイン
xxx.xxx.com
住所→座標
GET /v1/geocode?address=...&provider=abrg|gsi|nominatim
座標→住所(逆引き)
GET /v1/reverse?lat=..&lon=..&provider=gsi|nominatim
EXIF→住所
POST /v1/exif/reverse(multipart file=@photo.jpg)
内部
ABR: http://127.0.0.1:3000/geocode / Flask: unix:/run/geoapi/geoapi.sock

同居nginx環境の最大の罠は server_name重複/.well-known がFlaskに流れる こと。 ここを外すと Let’s Encrypt が失敗→レート制限になります。

2. 全体構成

Internet(443)
  ↓
Nginx (xxx.xxx.com)
  ↓ proxy_pass unix:/run/geoapi/geoapi.sock
Gunicorn + Flask (geoapi.service)
  ├─ /v1/geocode → ABR(abr-geocoder) http://127.0.0.1:3000/geocode
  └─ /v1/reverse → GSI reverse API(外部)
ABR server (abrg.service) :3000 (localhostのみ)

公開ポート80/443のみ(ABR:3000は外に出さない)

3. 事前準備(DNS / FW)

  • DNS:xxx.xxx.com の Aレコード → サーバIP(AAAA無しでもOK)
  • FW:80/443 を許可(UFW例)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status

4. Ubuntu 基本セットアップ

sudo apt update
sudo apt install -y nginx curl sqlite3 ca-certificates \
  python3-venv python3-pip

Node.js 20(ABR用)

curl -sL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node -v
npm -v

5. 配置先・ユーザー

sudo adduser --system --group --home /opt/geoapi geoapi
sudo mkdir -p /opt/geoapi/{abrg,flask}
sudo chown -R geoapi:geoapi /opt/geoapi

以降、ABRデータは /opt/geoapi/abrg/data、Flaskは /opt/geoapi/flask を前提。

6. ABR(abr-geocoder)構築

インストール

sudo npm install -g @digital-go-jp/abr-geocoder
abrg --help

データ生成(例:東京都 130001)

sudo -u geoapi mkdir -p /opt/geoapi/abrg/data
sudo -u geoapi abrg download -c 130001 -d /opt/geoapi/abrg/data

systemd:/etc/systemd/system/abrg.service

[Unit]
Description=ABR Geocoder (abrg) REST server
After=network.target

[Service]
User=geoapi
Group=geoapi
WorkingDirectory=/opt/geoapi
ExecStart=/usr/bin/abrg serve start -d /opt/geoapi/abrg/data -p 3000
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target

有効化と疎通

sudo systemctl daemon-reload
sudo systemctl enable --now abrg
sudo systemctl status abrg --no-pager

curl "http://127.0.0.1:3000/geocode?address=東京都千代田区丸の内1-9-1"

7. Flask(Gunicorn)構築

Flaskは「統一API」と「キャッシュ」「provider切替」を担当。ABR/GSIは裏で切替。

アプリ配置

  • /opt/geoapi/flask/app.py にFlaskコードを配置
  • 重要:gunicornでは __main__ が走らないので、DB初期化は import時に必ず実行

必須修正(例:cacheテーブル作成)

# app.py で init_db() 定義の直後にこれを置く
init_db()  # ← gunicorn起動でも必ず走る(no such table: cache を防ぐ)

venv & 依存

sudo -u geoapi python3 -m venv /opt/geoapi/flask/.venv
sudo -u geoapi /opt/geoapi/flask/.venv/bin/pip install -U pip
sudo -u geoapi /opt/geoapi/flask/.venv/bin/pip install flask gunicorn requests pillow

systemd:/etc/systemd/system/geoapi.service

[Unit]
Description=Geo API (Flask via Gunicorn)
After=network.target abrg.service
Requires=abrg.service

[Service]
User=geoapi
Group=www-data
WorkingDirectory=/opt/geoapi/flask
Environment="PYTHONUNBUFFERED=1"
# 公開するなら APIキー推奨
# Environment="API_KEY=YOUR_SECRET"
ExecStart=/opt/geoapi/flask/.venv/bin/gunicorn \
  --workers 2 \
  --bind unix:/run/geoapi/geoapi.sock \
  --umask 007 \
  app:app
Restart=always
RestartSec=2
RuntimeDirectory=geoapi

[Install]
WantedBy=multi-user.target

有効化・ソケット確認

sudo systemctl daemon-reload
sudo systemctl enable --now geoapi
sudo systemctl status geoapi --no-pager
ls -l /run/geoapi/geoapi.sock

切り分け(Nginx抜きで叩く)

curl --unix-socket /run/geoapi/geoapi.sock -G "http://localhost/v1/geocode" \
  --data-urlencode "address=東京都千代田区丸の内1-9-1" \
  --data-urlencode "provider=abrg"

8. Nginx(同居前提の設定)

server_name 重複は禁止(同じドメインが複数ファイルにあると片方 ignored)。

HTTP(80)まず通す:/etc/nginx/sites-available/giocode

server {
  listen 80;
  listen [::]:80;
  server_name xxx.xxx.com;

  # ACME は必ず Nginx が返す(Flaskに流すと認証失敗)
  location ^~ /.well-known/acme-challenge/ {
    root /var/www/html;
    default_type "text/plain";
    try_files $uri =404;
  }

  location / {
    proxy_pass http://unix:/run/geoapi/geoapi.sock;
    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;
  }
}

有効化

sudo ln -s /etc/nginx/sites-available/giocode /etc/nginx/sites-enabled/giocode
sudo nginx -t && sudo systemctl reload nginx

ACME到達テスト(絶対やる)

sudo mkdir -p /var/www/html/.well-known/acme-challenge
echo ok | sudo tee /var/www/html/.well-known/acme-challenge/ping.txt >/dev/null

curl -i "http://<PUBLIC_IP>/.well-known/acme-challenge/ping.txt" -H "Host: xxx.xxx.com"
# 200 OK + ok が返れば合格

server_name重複チェック

sudo nginx -T | grep -n "server_name giocode\.disasterinformation\.jp"

9. HTTPS(Let’s Encrypt / webroot方式推奨)

同居環境は –nginx より –webroot が安全。

staging(予行)

sudo apt install -y certbot
sudo certbot certonly --staging --webroot -w /var/www/html -d xxx.xxx.com

本番

sudo certbot certonly --webroot -w /var/www/html -d xxx.xxx.com
sudo systemctl restart nginx

証明書確認(staging混入を防ぐ)

sudo openssl x509 -in /etc/letsencrypt/live/xxx.xxx.com/fullchain.pem -noout -issuer
echo | openssl s_client -connect xxx.xxx.com:443 \
  -servername xxx.xxx.com 2>/dev/null \
  | openssl x509 -noout -issuer -subject

HTTPSのNginx完成形(80→443リダイレクト)

server {
  listen 80;
  listen [::]:80;
  server_name xxx.xxx.com;

  location ^~ /.well-known/acme-challenge/ {
    root /var/www/html;
    default_type "text/plain";
    try_files $uri =404;
  }
  location / { return 301 https://$host$request_uri; }
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name xxx.xxx.com;

  ssl_certificate     /etc/letsencrypt/live/xxx.xxx.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/xxx.xxx.com/privkey.pem;

  client_max_body_size 20m;

  location / {
    proxy_pass http://unix:/run/geoapi/geoapi.sock;
    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;
  }
}

反映

sudo nginx -t && sudo systemctl reload nginx

10. 呼び出し方法(クライアント)

Windows PowerShellは curl が別物なので curl.exe を使う。

住所→座標(ABR)

curl.exe -G "https://xxx.xxx.com/v1/geocode" ^
  --data-urlencode "address=東京都千代田区丸の内1-9-1" ^
  --data-urlencode "provider=abrg"

逆引き(座標→住所)

curl.exe -G "https://xxx.xxx.com/v1/reverse" ^
  --data-urlencode "lat=35.681382" ^
  --data-urlencode "lon=139.766084"

EXIF→住所(GPSがあるJPEG)

curl.exe -F "file=@photo.jpg" https://xxx.xxx.com/v1/exif/reverse

11. 運用・ログ・復旧コマンド

# 状態
sudo systemctl status abrg geoapi nginx --no-pager

# ログ
sudo journalctl -u geoapi -n 200 --no-pager -o cat
sudo journalctl -u abrg -n 200 --no-pager -o cat

# 再起動
sudo systemctl restart abrg
sudo systemctl restart geoapi
sudo systemctl restart nginx

# 更新テスト
sudo certbot renew --dry-run

典型トラブル

  • LE失敗→レート制限/.well-known がFlaskへ流れてないか(Hostヘッダcurlで200確認)
  • staging証明書のまま:opensslのissuerに (STAGING) が出てないか
  • Flask 500sqlite3.OperationalError: no such table: cache → import時 init_db()
  • ABR接続不可curl http://127.0.0.1:3000/geocode?... systemctl status abrg
  • Nginx同居の衝突nginx -T | grep server_name で重複を潰す

12. 別環境へ展開する時のチェックリスト

  • DNS Aレコードが新サーバIPを向いている
  • Nginxに server_name xxx.xxx.com が1つだけ
  • ACMEパスがNginxで200になる(Hostヘッダcurl)
  • ABR:3000 が localhost で稼働
  • geoapi.sock が作られ、Nginxがアクセスできる権限(Group=www-data / umask 007)
  • 証明書は本番(issuerにSTAGINGが出ない)
  • 外部curlで /v1/geocode /v1/reverse がJSONを返す

このHTMLは「別環境にコピーして、そのまま手順書」として使う目的で作ってあります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA