OpenVPNとnginxをOpenVPNのPort Share機能で共存させる

TCP 443番ポートは、一般にHTTPSの通信に使われ、ファイアウォールやプロキシによる制限の強いネットワークでも通過できることが多い。 一方、WebサーバをホストしたいIPアドレスと、443番ポートでVPNをホストしたいIPアドレスが同一の場合、443番ポートの取り合い(ポート番号の重複)が起きてしまう。 OpenVPNには、OpenVPNが待ち受けるポートへの通信が、 VPNのパケットか、VPN以外のパケット(例えばnginxへのHTTPS通信)かを自動で判別して、 VPN以外のパケットを中継してくれるPort Share機能がある。 つまり、OpenVPNが443番(0.0.0.0:443)で待ち受け、 nginxは他の適当なポート(例えば127.0.0.1:4443)で待ち受けるようにして、 Port Share機能の転送先をnginxに設定すれば、443番で待ち受けるOpenVPNと、本来443番で待ち受けたいnginxとが共存できる。 UbuntuサーバへのOpenVPNの導入は、以下のDigitalOceanの記事が有用なので、参照されたい。 OpenVPNで使用するサーバー証明書・クライアント証明書を発行するCAサーバをセットアップする記事: https://www.digitalocean.com/community/tutorials/how-to-set-up-and-configure-a-certificate-authority-ca-on-ubuntu-20-04 OpenVPNをセットアップする記事: https://www.digitalocean.com/community/tutorials/how-to-set-up-and-configure-an-openvpn-server-on-ubuntu-20-04-ja OpenVPNのインストールにあたっての重要な点として、 ステップ7 — OpenVPNの設定の(オプション)DNSの変更をプッシュして、VPNを介してすべてのトラフィックをリダイレクトするを実行した上で、 ステップ9 — ファイアウォールの設定を手順通り実行することがある。 NAT下にあるなどの理由でufwの設定をしていなかったサーバーでも、新たにufwの設定をすることで、トラブルなくOpenVPNのインストールができる。 このステップを行わないと、VPN外へのパケットの転送が動作せず、VPN接続中のクライアントがインターネットに接続できない状況に陥る。 また、(オプション)ポートとプロトコルの調整で、待ち受けポートを443番、プロトコルをTCPにしておく。 OpenVPNの起動の際には、nginxとポート番号を取り合って起動に失敗しないように、nginxをあらかじめ停止し、ポート番号を書き換えておく。 nginx 設定ファイル /etc/nginx/sites-enabled/などにあるnginxの設定ファイルを書き換え、 4443番で待ち受けるようにする。 server { listen 4443 http2 ssl; } 大量にサイトをホストしている場合、コマンドやVSCodeなどでまとめて書き換えるとよい。 /etc/openvpn/server/server.conf OpenVPNのサーバー設定ファイルにport-shareを追記する。 port 443 port-share 127.0.0.1 4443 proto tcp OpenVPNからnginxへのパケット転送の許可(ufw) ufw allow from 10.8.0.0/24 to any port 4443 nginx, OpenVPNの再起動 nginxおよびOpenVPNを再起動し、443番ポート宛てのHTTPS通信(nginx宛て)、443番ポート宛てのVPN接続(OpenVPN宛て)が正常に動作することを確認する。

2022年10月19日 · aoirint

Adobe Acrobat ReaderのUIが正しく描画されない・印刷しようとするとクラッシュする(Windows 10 21H2)

特定のWindows 10 21H2環境で、Adobe Acrobat ReaderのUIが正しく描画されなかったり、PDFを印刷したりするとクラッシュする症状に悩まされていた。 https://twitter.com/aoirint/status/1579530951029579776 症状 一部のテキスト(太字?)が右上に傾いて表示される 一部のテキスト(ボタンのラベル?)が表示されない 一部のテキストが135度左回転して表示される ボタンのサイズが本来より大きくなる 印刷UIを開くとクラッシュする メニューから印刷を選んで印刷UIを開くとクラッシュする。 クラッシュレポート送信ダイアログも表示されない。 ほとんどのテキストが太字・下線付きで表示される 高DPI設定を変更すると、表示されなかった一部のテキストを表示できることがあるが、太字・下線付きで表示される。 高DPI設定(Acrobat.exeのプロパティ>互換性>高DPI設定の変更) おかしい表示 正しい表示(解決後のスクリーンショット) 自分の環境での原因・解決 原因は、Windowsのデフォルトフォントを変更していたことだった。 Windowsのデフォルトフォントは、(おそらくこういった不具合を防ぐため)通常の設定UIでは変更することができない。 レジストリを書き換えることで、フォント名に対応するフォントを変更することができる。 このとき、標準的にWindowsのUIフォントとして使われるSegoe UIフォントで描画する、という指定がされているUI上のテキストを、別のフォントを使って描画するように設定することで、デフォルトフォント(システムフォント)を変更する方法がある。 デフォルトフォントの変更方法を指南する記事: https://techcult.com/change-default-system-font-in-windows-10/ Acrobat Readerを正常に動作させるには、Segoe UIとして描画されるフォントが、正しくSegoe UIフォントである必要があるらしい。 クラッシュの原因についてSegoe UIフォントの正常性との関係を指摘するコメント: https://community.adobe.com/t5/acrobat-reader-discussions/acrobat-reader-quit-unexpectedly/m-p/11139813#M66281 上のデフォルトフォントの変更方法についての記事を参照し、復元用regファイルを作成・実行、Windowsを再起動することで、Acrobat Readerを正常に動作させることができるようになった。 recover.reg (TechCultより) Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts] "Segoe UI (TrueType)"="segoeui.ttf" "Segoe UI Black (TrueType)"="seguibl.ttf" "Segoe UI Black Italic (TrueType)"="seguibli.ttf" "Segoe UI Bold (TrueType)"="segoeuib.ttf" "Segoe UI Bold Italic (TrueType)"="segoeuiz.ttf" "Segoe UI Emoji (TrueType)"="seguiemj.ttf" "Segoe UI Historic (TrueType)"="seguihis.ttf" "Segoe UI Italic (TrueType)"="segoeuii.ttf" "Segoe UI Light (TrueType)"="segoeuil.ttf" "Segoe UI Light Italic (TrueType)"="seguili.ttf" "Segoe UI Semibold (TrueType)"="seguisb.ttf" "Segoe UI Semibold Italic (TrueType)"="seguisbi.ttf" "Segoe UI Semilight (TrueType)"="segoeuisl.ttf" "Segoe UI Semilight Italic (TrueType)"="seguisli.ttf" "Segoe UI Symbol (TrueType)"="seguisym.ttf" "Segoe MDL2 Assets (TrueType)"="segmdl2.ttf" "Segoe Print (TrueType)"="segoepr.ttf" "Segoe Print Bold (TrueType)"="segoeprb.ttf" "Segoe Script (TrueType)"="segoesc.ttf" "Segoe Script Bold (TrueType)"="segoescb.ttf" [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes] "Segoe UI"=-

2022年10月15日 · aoirint

ARK: Survival Evolved Dedicated Server

以下のDockerイメージを使う。 https://hub.docker.com/r/hermsi/ark-server/ docker-compose.yml イメージのタグは適宜最新のものに更新する。 version: '3.8' services: ark: image: hermsi/ark-server:tools-1.6.61a restart: always volumes: - ./ark-server:/app - ./ark-server-backups:/home/steam/ARK-Backups environment: - SESSION_NAME=${SESSION_NAME} - SERVER_MAP=${SERVER_MAP} - SERVER_PASSWORD=${SERVER_PASSWORD} - ADMIN_PASSWORD=${ADMIN_PASSWORD} - MAX_PLAYERS=${MAX_PLAYERS} - UPDATE_ON_START=${UPDATE_ON_START} - BACKUP_ON_STOP=${BACKUP_ON_STOP} - PRE_UPDATE_BACKUP=${PRE_UPDATE_BACKUP} - WARN_ON_STOP=${WARN_ON_STOP} ports: # Port for connections from ARK game client - "0.0.0.0:7777:7777/udp" # Raw UDP socket port (always Game client port +1) - "0.0.0.0:7778:7778/udp" # RCON management port - "127.0.0.1:27020:27020/tcp" # Steam's server-list port - "0.0.0.0:27015:27015/udp" .env SESSION_NAME=my-ark-session-name SERVER_MAP=TheIsland SERVER_PASSWORD=myserverpasword ADMIN_PASSWORD=myadminpassword MAX_PLAYERS=10 UPDATE_ON_START=false BACKUP_ON_STOP=false PRE_UPDATE_BACKUP=true WARN_ON_STOP=true ポート公開 詳細は調査中。 ...

2022年7月30日 · aoirint

Python, asyncioを使った同期・非同期処理の実装例

Python 3.9.13 (pyenv) Ubuntu 20.04 (WSL2) https://github.com/aoirint/python_asyncio_examples なんかこう書くとうまく動くということしかわからん、という実装例です。 https://twitter.com/aoirint/status/1544891079786627074 基本実装 同期関数から非同期関数を同期的に呼び出す asyncio.run Details import asyncio import time def main(): async def func(): await asyncio.sleep(3) print('func exited') # 1 asyncio.run(func()) time.sleep(1) print('main exited') # 2 main() print('exited') # 3 同期関数から非同期関数を非同期的に呼び出す threading.Thread + asyncio.run Details import asyncio from concurrent.futures import ThreadPoolExecutor import threading import time def main(): async def func(): await asyncio.sleep(3) print('func exited') # 3 thread = threading.Thread(target=lambda: asyncio.run(func())) thread.start() time.sleep(1) print('main exited') # 1 main() print('exited') # 2 非同期関数から同期関数を同期的に呼び出す ふつうに呼び出す Details import asyncio import time async def main(): def func(): time.sleep(3) print('func exited') # 1 func() await asyncio.sleep(1) print('main exited') # 2 asyncio.run(main()) print('exited') # 3 非同期関数から同期関数を非同期的に呼び出す asyncio.new_event_loop + ThreadPoolExecutor + EventLoop.run_in_executor Details import asyncio from concurrent.futures import ThreadPoolExecutor import time async def main(): def func(): time.sleep(3) print('func exited') # 3 loop = asyncio.new_event_loop() executor = ThreadPoolExecutor() loop.run_in_executor(executor, func) await asyncio.sleep(1) print('main exited') # 1 asyncio.run(main()) print('exited') # 2 非同期関数から非同期関数を同期的に呼び出す awaitキーワード Details import asyncio async def main(): async def func(): await asyncio.sleep(3) print('func exited') # 1 await func() await asyncio.sleep(1) print('main exited') # 2 asyncio.run(main()) print('exited') # 3 非同期関数から非同期関数を非同期的に呼び出す threading.Thread + asyncio.run Details import asyncio import threading async def main(): async def func(): await asyncio.sleep(3) print('func exited') # 3 thread = threading.Thread(target=lambda: asyncio.run(func())) thread.start() await asyncio.sleep(1) print('main exited') # 1 asyncio.run(main()) print('exited') # 2 非同期関数から同期間数を非同期的に3つずつ呼び出す asyncio.new_event_loop + ThreadPoolExecutor + EventLoop.run_in_executor Details import asyncio from concurrent.futures import ThreadPoolExecutor import time async def main(): def func(): time.sleep(3) print('func exited') # 3 loop = asyncio.new_event_loop() executor = ThreadPoolExecutor(max_workers=3) loop.run_in_executor(executor, func) loop.run_in_executor(executor, func) loop.run_in_executor(executor, func) loop.run_in_executor(executor, func) loop.run_in_executor(executor, func) loop.run_in_executor(executor, func) loop.run_in_executor(executor, func) loop.run_in_executor(executor, func) loop.run_in_executor(executor, func) await asyncio.sleep(1) print('main exited') # 1 asyncio.run(main()) print('exited') # 2 よく見るエラー RuntimeError: Event loop is closed TBW ...

2022年7月7日 · aoirint

nginx, リバースプロキシからのReferrer-Policyヘッダを置換する

add_header Referrer-Policy no-referrer; # add_header Referrer-Policy same-origin; proxy_hide_header Referrer-Policy; # remove Referrer-Policy from original response https://takuya-1st.hatenablog.jp/entry/2018/11/01/040000 https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Referrer-Policy https://stackoverflow.com/a/55692346 Mastodon Mastodonでリファラを送らないようにしたかった。 HTMLタグのmetaタグを使う方法をよく使うのだけれど、 ブログとかによくあるheadタグへの任意HTML追加機能のようなものは Mastodon v3.5.3にはなさそうだった。 https://github.com/mastodon/mastodon/issues/9183 同一オリジンでもリファラを送らないようにする(no-referrer)とMastodonの一部の設定が更新できなくなくなるようなので、 MastodonではReferrer-Policy: same-originに設定した。 単純にadd_headerするだけだと、Mastodonが返すReferrer-Policyとnginxが追加するReferrer-Policyで2つのヘッダになってしまった。 referrer-policy: origin referrer-policy: no-referrer そこで、 proxy_hide_header Referrer-Policy; でMastodonから返ってきたReferrer-Policyを削除するようにした。 あとは、 add_header Referrer-Policy same-origin; するだけ。 https://mstdn.aoirint.com/@aoirint/108569086590516035

2022年7月1日 · aoirint

MSFS2020の追加ダウンロードファイルを別ディスクに移動する

Microsoft Flight Simulator Game of the Year Edition (MSFS2020) https://store.steampowered.com/app/1250410/Microsoft_Flight_Simulator_Game_of_the_Year_Edition/ MSFSはSteamライブラリで見ると1GBくらいだけれど、 起動後に100GB以上の追加ファイルをダウンロードする。 これがメインディスクを圧迫するので、多少のパフォーマンス悪化を覚悟してサブディスクに移動する。 %APPDATA%\Microsoft Flight Simulator\UserCfg.optを開く。末尾の InstalledPackagesPath "C:\Users\myuser\AppData\Roaming\Microsoft Flight Simulator\Packages" を好きなディレクトリに書き換える。 InstalledPackagesPath "D:\Microsoft Flight Simulator\Packages" あとは実体をエクスプローラで移動させればOK。 参考 https://jp.fl510.aero/index.php/msfs/blog/msfs2020-known-issues-list

2022年6月29日 · aoirint

Django 3.xから4.xへの更新でPOSTリクエスト時にCSRF検証に失敗する

想定: 3.xで動いていたフォーム送信が4.xへの更新でCSRF検証に失敗するために動かなくなった settings.pyにCSRF_TRUSTED_ORIGINSを追加すればよい。 https://docs.djangoproject.com/en/4.0/ref/settings/#std-setting-CSRF_TRUSTED_ORIGINS Origin: e.g. https://example.com https://developer.mozilla.org/ja/docs/Glossary/Origin CSRF検証のドキュメントを3.xと比べると、以下の記述が増えている。 CsrfViewMiddleware verifies the Origin header, if provided by the browser, against the current host and the CSRF_TRUSTED_ORIGINS setting. This provides protection against cross-subdomain attacks. 4.x: https://docs.djangoproject.com/en/4.0/ref/csrf/#how-it-works 3.x: https://docs.djangoproject.com/en/3.2/ref/csrf/#how-it-works

2022年6月24日 · aoirint

ニコニコ生放送のお絵描き放送ネタでペンタブレットを使う

ニコニコ生放送のお絵描き放送ネタで、ペンタブで描こうとしたらページがスクロールしてしまった。 これを防ぎたい。 開発者ツールから以下を実行する。 document.body.style = 'margin: 0; height: 100%; overflow: hidden;' 元に戻すには(bodyタグにstyle属性がない場合)、 document.body.style = ''

2022年6月24日 · aoirint

えやみぐさの記事運用 2022-06-24

技術ノートチャンネルには「具体的な解決策が見つかったものを報告・共有する記事」を載せたかったかもしれない。 わかりませんでした。いかがでしたか? を避けたい。 でも、具体的な解決策がわからないんだけど、これどうしたらいいのか悩んでる、ということを共有する記事もほしい。 Twitterに投げるには分量が多いとか。 未解決タグを付ける方法はありそう? でも20%くらい解決したんだけど…みたいな場合に中途半端な未解決タグが付きそう。 前の記事を参照して、解決策1個みつけたわ、みたいな記事があってもいいと思うんだけど、それが100%の解決策でなかったりする場合にベストアンサーではないよねみたいなことがある。 質問IDでも振って紐づけるか??? この記事にリンクしている記事一覧とかあればそれでいいのか?(実装が面倒かも?) まあタイトル詐欺しなければどういう運用しても別にいいのでは… 記事が増えすぎて質が落ちる・埋もれるかもしれんという問題はあるかも? 先にJoplinとかScrapboxとかである程度整理してからの方が雑記事になりにくそう。 そういうのを作業ログチャンネルに入れたかったんだけど、なんだかんだそのレベルの文章をアップロードするのは面倒くさい。 記事としてのまとまりが悪くなりがちな気がする(話題があちこち飛んだり、矛盾した考えがあったりする)。 JoplinとかScrapboxに書くのがちょうどいい? うーん。 https://blog.aoirint.com/entry/2022/pip_compile_metadata_generation_failed/ 上を書くにあたって、Joplinに下書きして、記事としてまとめたものを公開して、下書きをScrapboxに公開する、とバージョン違いのコピーが3個できた。 Joplin: コンセプトがはっきりしないMarkdownの下書き ブログ: 一応方針を固めたもの、Markdown Scrapbox: Joplinの下書きをScrapbox書式に修正したもの これがこういうバージョン違いなんですよ、ということを説明するDBがほしくなる。 バージョンの同期とか面倒だし、あんまりいろんなところに分散させたくないな、とは思うんだけど、いきなりScrapboxに書くのは軽重問わずセンシティブな情報が事故で公開されるということが起きそうで怖い。 でも正直、バージョン管理とか面倒なことを考えているのは無駄な気もする。 記事を書くモチベーションを上げたいんだけど、それとは関係ないのではと思った。 今回については、はじめは自分用のメモのつもりで書いていたけど、Joplinだとどんどん新しいノートが増えて埋もれるし、あんまり検索にヒットしなくて公益性があるなと思ったから記事化した。 埋もれることについては、だいたいキーワードを総当たりの文字列検索でなんとかなるんだけど、ちょっとしたメモ書きは整理するのが難しいし、Joplin上には1700ノートくらい、Evernoteにはツイートとかも保存しているから42000ノートくらいあって、この中に埋もれさせるのは微妙な感じがする… それよりも、SSGに10分かかるのが微妙。 あと、noindexした記事がGitHubの公開リポジトリを通じてGitHub Searchにひっかかったり、Googleにインデックスされる可能性があったり、いまの実装だとnoindexなのにサイトマップに送信されてしまったりが微妙。 雑記チャンネルは、検索性・一覧性を悪くするためにわざとタイトルを付けなかったり、複数の内容を1記事に収めたりしていたんだけど、古いやつをちょっと分割してみた。 粗探しをする人とかエゴサーチャーとか正義の晒し屋とか伝書鳩とかに見つかりにくくしたいんだけど、ある程度こなれてきたらいいのかなとちょっとだけ思った(麻痺)。

2022年6月24日 · aoirint

GitHub ActionsでPyPIにPythonパッケージをpushする(GitHub Release連携でバージョン付け)

https://qiita.com/aoirint/items/09ea153751a65bf4876f#github-release%E4%BD%9C%E6%88%90%E6%99%82%E3%81%ABpypi%E3%81%AB%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89 上の記事のWorkflowテンプレートをちょっと改良した。 GitHub Release作成時にリリースタグをパッケージバージョンにしてpush 構成 mypackage/__init__.pyに以下のように開発用のバージョン情報を記述する。 リリース時にGithub Actionsでリリースタグに置換してからPyPIにpushする。 __VERSION__ = '0.0.0' GitHub Secrets PYPI_API_TOKEN GitHub Workflow .github/workflows/pypi.yml name: Publish a package to PyPI on: release: types: - created env: VERSION: ${{ github.event.release.tag_name != '' && github.event.release.tag_name || '0.0.0' }} jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup Python uses: actions/setup-python@v2 with: python-version: 3.x - name: Install Dependencies run: | pip3 install -r requirements.txt pip3 install wheel - name: Replace version run: | sed -i "s/__VERSION__ = '0.0.0'/__VERSION__ = '${{ env.VERSION }}'/" mypackage/__init__.py - name: Build Package run: python3 setup.py sdist bdist_wheel - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.PYPI_API_TOKEN }}

2022年6月24日 · aoirint