不正アクセスログ集計ツール④

前回の記事でパイプ接続したプロセスをmapのまま返すとプロセスが終らないまま関数から帰ってきてしまうので、気持ち悪いからlist関数を使ったが、

bipset =  list(map(lambda x: ipv4adrset(x.decode('UTF-8').rstrip('\n')), proc.stdout))
 ↓
bipset =  [ipv4adrset(x.decode('UTF-8').rstrip('\n')) for x in proc.stdout]

の様に、わざわざmap使うより、下のようにリスト内包表記で直接リストを返すような仕組みを用いた方がスマートな気がした。とくに今回のようにmap直後にlistするような使い方の場合特に。

mapやfilterはイテレータなので直後にforなどのループ処理を行なう場合に適しており、リストそのものが欲しいときにはmapを使わずに[リスト内包表記]をするのが良いきがする。リスト内包表記やlist式のリスト生成では各項目の変換式(関数)が一度に使用され結果のリストが返されるが、イテレータでは生成段階では変換式(関数)は実行されず、for文など繰返し処理が行なわれる時に一つずつ実行されることになる。

たとえばファイルを読み込み関数があったとして、オープンしたファイルハンドルに対して読み出して検索や加工をする処理の結果をイテレータとして返してしまうと、関数からリターンした段階でファイルを閉じると、そのイテレータからは読み出せないという結果になる。

ということでその場合は、リストとして返す関数が正解となる。

あと、イテレータからリストに変換するときに一度繰返し処理が行なわれるという考え方からすると、for文に使用する前にリストに変換するのは効率が悪く。動作速度的にも不利になるようなので、そういう観点で使い分けていく目安になるのではないかと思う。

次に、ログファイルの解析部分。これも前回記事で、djangoの認証バックエンドをチョットいじって、ログイン失敗のログを残せるようにしたので、ここではそれを検出してリストとして返すこととする。ログファイルはApacheユーザーに読取り権限があるので、そのまま読見込めばいい。ただし、/var/logに保存している場合など、logrotateの処理が行なわれる場合それも追跡して行ないたい。また古いログはrotate時にgzip圧縮されるのでこれにも対応したい。

from blocklib import ipv4adrset
import os, glob, gzip
logger = getLogger(__name__)
import re, json

# djangoのアクセスログ(json形式)を読み込に認証履歴のレポートを返す
# 認証履歴のログはdjango認証バックエンドを継承して認証時のログ出力機能を追加したもの
# [引数]djlog : 解析するアクセスログ(json形式)をフルパスで与える(gzipもOK)
#              Noneの場合は、デフォルト django_log_json を使用(logorotateされたものも含み全てを読み込む)
#       st : レポート対象の開始日時(logrotateされたファイルはこの日時より新しいものを読み込み対象とする)
#       ed : レポート対象の終了日時
#       address : レポート対象のIPアドレスオブジェクト(Noneの場合は全て)サブネット検索対応
def get_django_loginfails(djlog, st, ed, address=None):
    if djlog is not None:
        djlogs = [djlog]
    else:
        djlogs = [x for x in glob.glob(django_log_json + '*') if re.match('.*(log|gz|[0-9])',x) and os.path.getmtime(x) > st.timestamp()]
        djlogs.sort(key=lambda x: os.path.getmtime(x))
    retlist = []
    for jlog in djlogs:
        logger.debug(jlog)
        with open(jlog, 'r') if not re.match('.*\.gz$', jlog) else gzip.open(jlog, 'rt') as jf:
            #jl = json.load(jf)
            decoder = json.JSONDecoder()
            jlines = map(lambda x: decoder.raw_decode(x), jf)
                #aa = decoder.raw_decode(line)
            for jl in map(lambda x: x[0], jlines):
                # fromisoformatで読み込むために末尾のZが邪魔なので削除
                # UTCのタイムゾーンを設定してJST時刻に変換する
                ts = datetime.fromisoformat(jl['timestamp'].rstrip('Z')).replace(tzinfo=timezone.utc).astimezone(tz_jst)
                ts = ts.replace(microsecond=0)
                if ts > st and ts < ed:
                    (dat, event) = (jl['ip'], jl['event'])
                    res0 = re.match('user logged in : (.+)$', event)
                    res1 = re.match('login faild.*: (.+)$', event)
                    event = False if res1 else True if res0 else None
                    if event is None:
                        continue
                    name = res1[1] if res1 else res0[1] if res0 else ''
                    if address is not None and address != ipv4adrset(dat):
                        continue
                    logger.debug('%s : %s - %s(%s)' % (str(ts), dat, name, event))
                    retlist.append(
                        {
                            'name':name,
                            'datetime':ts,
                            'address':ipv4adrset(dat),
                            'status':event,
                            'source':'django',
                        }
                    )
                    #print('%s : %s : %s' % (str(ts), dat, event))
    return retlist

ログはdjaongo.structlogでjson形式で出力したものを対象としている

  • 17行目globクラスを使用して指定したファイル名で始まるlogrotateファイルのリストを作成する(検索開始日付stよりも新しいタイムスタンプのファイルという条件も含める)
  • それぞれに対して、ファイルオープンし(拡張子gzだったらgzipオープンに変更)1行ずつ読み出し、対象パターンを見つけたら辞書形式のデータの配列として返す

ソースプログラムを貼付けてるけど、実際はそのままでは動かない一部の公開なので誰の役にも立たないただの覚え書きなのであった。
json形式だからさっくり読めるだろうとして始めたら何かエラーになってサッパリ読めない。。何でだろうと思って先人様たちの記事をたどって調べたら、こんなもんだと上記のようにデコーダを作って1行ずつ読み込んでいくようだ。
ぇぇぇーーー。同じくpython使ってjson形式のログを掃き出してるのになんで直接読めないん??ってなった。こんど時間があったら調べてみよう

不正アクセスログ集計ツール③

パート3と思ったけど、ちょっとdjango開発環境にて問題発生。

Ubuntuサーバー(さくらVPS)上のコンテンツを編集するのに、いろいろゴタゴタした顛末を下記に

  • sshログイン出来るユーザーでremote-SSHのVScodeでdjangoプロジェクトのコンテンツ編集を行なう。
  • このままではプロジェクトのファイル所有者やアクセス権がユーザーのものになってしまうので、Apacheユーザーで動作する本番環境を直接編集するわけには行かない。
  • そこで一旦GitHubプライベートリポジトリにpushして、Apacheユーザーで本番環境にpullすることで動作させることとした。
  • しかし、ちょっとした修正さえ編集して動作を確認するためにpush/pullを繰り返すこととなり、Git履歴がメッチャ汚くなる(一旦pushしてしまうと例え一人で使用しているとはいえrebaseとか履歴編集が容易ではない)。
  • いっそApacheユーザーでSSHログイン出来るようにしようかと、血迷ったことを考えたが、すんでの所で思いとどまる。
  • 既にApache2環境にデプロイ済のポータルプロジェクトだが、ユーザー環境ではもう一度python manage.py runserverで動作させてある程度動作検証した後に本番環境へpushするという流れにしようとした。
  • 注意点は、データベースは同じものを使用するので壊さないように注意。
  • ログファイルなど本番用と混ざらないように、別ログになるようにする
# settings.py で動作中のユーザー名を得る(テスト環境であればローカルユーザーになる)
RUN_USER = pwd.getpwuid(os.stat(__file__).st_uid).pw_name

# ユーザー名でApache2で動作中かどうかを判別してログのベースディレクトリを変更
LogBase = '/var/log/django' if RUN_USER == APACHE_USER else os.path.join(BASE_DIR, '.log')

# あとはログの仕様で設定する
  • 一応デプロイ後のものと同じ構成でdjango runserverテスト環境でも動作することを確認できたが、画像であるとかstaticが読み込めなくなっていた。(Apacheではサーバーの設定でstaticのエイリアス設定をしていたので、djangoのURLconfでの動作はあまり見ていなかった)
  • 調べたところ、静的ファイルの設定はsettings.pyでSTATIC_URLとSTATIC_ROOTで設定してあったのだが、ウチの環境では動作せず(素の状態でdjango-admin startproject XXXX して試してみたがstaticディレクトリを読み取ることが出来なかった)。代わりにSTATICFILES_DIRSという配列を設定することで無事読み込めることが分かった。
STATIC_URL = '/static/'    # これはOK

STATIC_ROOT = os.path.join(BASE_DIR, 'static')
#   ↓
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

  • STATIC_ROOTとSTATICFILES_DIRSを同時に設定するのはダメ。
  • djangoの素の状態でこれでstaticが読み込めることが確認できたが、本番環境からpullしてきたポータルプロジェクトでは上記の修正を行なってもstaticが読み込めなかった。数時間掛けて原因究明した結果、単に404 Not Foundの状態をブラウザが覚え続けていただけで、ブラウザキャッシュクリアすることで無事読み込めるようになった。お粗末。

何ともアホらいいオチでしたが、ブラウザキャッシュは意外に見落としがち。以前のサーバー引越の時も新サーバーに以前のドメインを割り当ててても一向に変化が無くて困ったのも、結局はブラウザキャッシュが原因でした。

不正アクセスログ集計ツール②

不正アクセスに対する対応は当サイトでは悪質な(連続で何度もログインアタック攻撃をするなど)場合、手動でblocklist(ufwの場合、/etc/ufw/before.rules)に放り込むことにしている。そのため集計対象としてはブロックリストに含まれるIPアドレスは対象外としたい。よってapacheユーザーでブロックリストを読み込む必要があるが、こちらのファイルはroot権限でしか開くことが出来ない。apacheユーザーを管理者グループに入れることも考えたが、ここはひとつ。

  1. root権限でブロックリストを読み込むコマンドを作成する(getblocklist)。
  2. apacheユーザーに getblocklistコマンドだけパスワードなしでsudo出来るようにする。
  3. apacheユーザー権限で動作するpythonプログラム(djangoなど)でsubproccessにより上記コマンドを実行し、結果をリストとして得る関数を作る

で、バッチリではないかと、この方針で進めることとする。

1.root権限でブロックリストを取得するコマンド

これは全く問題なしで、以前のblockset.pyより該当部分のみを抜き出したプログラムとなる。

getblocklist.py

ipアドレスを利用するクラスipv4addressはライブラリとして分離している。

2.apacheユーザーに実行権限付加

表示プログラムを/usr/local/sbinなどに置きapacheユーザー(www-data)にsudo実行権限を与える

www-data        ALL=(ALL)       NOPASSWD:/usr/local/sbin/getblocklist.py

www-dataパスワード未設定のsu不可ユーザーなのでsudo ALLでも他のコマンドは実行出来ない。

3. apacheユーザー権限でリストを取得する

subproccessモジュールを利用して標準出力を得るには、Popenでプロセスを起動してプロセスの標準出力を接続する必要がある。プロセスのstdoutは一行づつ取り出すイテレータとなるので、mapによりipv4adrsetのリストとして取得している。(また、なぜかプロセスの出力がバイトとなっているので、UTF-8で文字列にデコードする必要があった”x.decode('UTF-8').rstrip('\n')”)

import subprocess

get_blocklist_proccess_cmd = ['sudo','/usr/local/sbin/getblocklist.py']

# root権限でブロックリスト取得コマンドを走らせて標準入力を得る
def get_blocklist():
    proc = subprocess.Popen(get_blocklist_proccess_cmd, stdout=subprocess.PIPE)
    bipset =  list(map(lambda x: ipv4adrset(x.decode('UTF-8').rstrip('\n')), proc.stdout))
    return bipset

良く分かっていなかったのだけど、関数からmapのまま返すとイテレータなので関数の外にでてもプロセスが終わってないのね。。listとして全部取得してプロセスを正常に終らせておく必要がありましたとさ。

不正アクセスログ集計ツール①

目的

不正アクセスのログを集計してポータルの管理ページに結果を表示する

不正アクセスの定義

今回の場合はWEBページの認証機構へのログインアタックとする。パスワードを知っていて入って来てしまう場合は対象外。この場合はログイン履歴表示機能で様子をみることが可能とする。

機能

  • djangoポータルページの管理グループのみ表示(ページへのリンクも管理グループのみに表示)
  • django認証ログからの集計と、Wordpressのプラグイン(User Login History)の認証履歴データベーステーブルからの履歴も取得し、合計として集計する。
  • 集計開始日時ー終了日時、リストアップするための認証失敗回数(5回など)設定。
  • 特定のIPアドレスのアクセス詳細を表示ー上記リスト表示にボタン追加

その他機能追加として、直接関係は無いが

  • エラー404などのページカスタマイズ
  • djangoいろいろ勉強用テストページ

現在の所、最終的な完成形は上記のような仕様になるが、管理ページの追加なので訪問者には何も関係が無いです。その他思いついたら仕様追記する予定。

開発に関しては、djangoのプロジェクトディレクトリをgit管理とし、GitHubプライベートリポジトリ経由でsshログインユーザーにclone。VScodeで編集してテストブランチとしてpush。apacheユーザーでプロジェクトディレクトリ(テスト用仮想サーバー)にpullして動作試験。デバッグを行い完成形(公開レベルになった段階)をmasterブランチにmergeしてGitHubにpush。公開用プロジェクトディレクトリにpullして運用するという流れ。

単純にapacheユーザーのプロジェクトをVScodeのssh-remoteで編集したいという欲求のため、このような複雑は構造となってしまった。GitHubの使い方の勉強できて丁度良いか。

旧サーバー停止

今年3月より行なってきたサーバー引越も先月終了。リファレンス用に稼働していた旧サーバー(marocha.marochanet.org)を今月末の契約終了を受けて本日停止しました。これをもって来月より新サーバー(jagha.marochanet.org)単独での運用になります。2013年7月から稼働してきた「さくらVPS(V3)2Gコース」。CentOS6にて運用開始し、2020年初頭にCentOS8にアップグレード。安定してきたところでCentOSサポート終了予定のお知らせ。それを受けてのサーバー引越でした。

さくら「VPS(V5)2GのSSD100Gコース」に無料でSSD100G追加キャンペーンに釣られての流れになるけど、Ubuntuサーバーへの引越と同時に出来て丁度良い感じでした。

まぁ、WEBサイト的には、見た目は何も変らないので変化を感じることは無いけど。。。

新サーバー(jagha):marocha君、8年間お疲れさまでした。
ちなみにmarochaはFinalFnatasyXIをプレイしていたときのメインキャラクター名(ホントはSemicolonというキャラがメインだったのだが、タルタル族の可愛さに徐々のサブキャラのmarochaで活動する機会が増え、最後にはサブがメインになってしまったというオチ)で、jaghaは現在プレイしているFinalFantasyXIVのメインキャラ名です。こちらにもmarochaというサブキャラが居るけど、今のところメインを乗っ取る気配は無さそうだ。。。

djangoセキュリティログ追加

チュートリアルを使用したdjangoの勉強と並行して、djangoで構成している本サイトのポータルページもある程度のセキュリティー対策が急がれる。djangoを素で使用しているサイトは少ないようでwordpressのようにBOTによる攻撃はまだ見られない。何らかのCMSを使用しているのを見越して適当なURLをぶっ込んでくるBOTは404で弾けるのであまり問題にならないが、ごくたまーに、しつこくadminでログインしようとする輩が現れるようだ。

このWordpressのサイトでも結構多かったので(普通に見に来てくれる人は殆ど居ないのにwww)、User Login Historyというプラグインを入れている。ここもたまに100回以上のadminログイン試行をしてくる輩がいるので、このログを利用してIPを特定しblockset.pyで手動だけどお引き取り願うことにしている。

同じような仕組みをdjangoのポータルページにも仕掛けようと勉強がてら色々と調べたところ、ログイン用の認証バックエンドという仕組みが利用できそうだということが分かった。デフォルトの<project>/setting.pyには明示的に定義はされていないが(django.conf.global_settings にデフォルト定義)、AUTHENTICATION_BACKENDSという配列がありここのカスタムや追加の認証バックエンドを追加出来る(<project>/settings にて再定義)

デフォルトでは’django.contorib.auth.backends.ModelBackend’が一つ定義されているので、こちらを継承カスタマイズして認証結果をログ出力できるようにする方針とする。

django.contrib.auth.backends.ModelBackend 抜粋
class ModelBackend(BaseBackend):
    """
    Authenticates against settings.AUTH_USER_MODEL.
    """

    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        if username is None or password is None:
            return
        try:
            user = UserModel._default_manager.get_by_natural_key(username)
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a nonexistent user (#20760).
            UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user
       ・・・・・・

認証判定にはメソッドauthenticateが機能しており、認証OKであればusernameを、NGであればNoneを返す関数であるため、クラス継承により下記のようにメソッドをオーバーライドして再定義する

<project>/backends.py
from django.contrib.auth.backends import ModelBackend
from logging import getLogger # using logging module

class ModelLogBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        logger = getLogger('loginInfo') # example
        res = super().authenticate(request, username, password, **kwargs)
        if res is None:
            logger.info('login faild, bad user: %s' % username)
        else:
            logger.info('user logged in : %s' % username)
        return res

super()で親クラスのメゾッドに丸投げして、結果に応じてログを吐き出す機構を追加。継承したクラスを新たなバックエンドとして<project>/settings.pyに定義する。

# Authntication backend
AUTHENTICATION_BACKENDS = [
    '<project>.backends.ModelLogBackend'
]

<project>はdjangoのプロジェクト名に置き換える。

ちなみにloggerの設定は別の記事を参照して完成しておくこと。当サイトの場合は他のアクセスログの都合でstructlogを使用している(設定さえしておけばloggingと同等に使用可能)。

もともと、ポータルとしてのdjangoサイトは出来上がっていたので、この機能を付けたくてdjangoの本格勉強を始めたという流れでした。蓋を開けてみると思ったより簡単で、同時にカスタマイズ性の高さに今更ながら感動です。次はdjabngo+bootstrap(japascript)による動的サイトの実装実験を目指したいな。

金魚飼育

何年か前の記事にメダカの飼育をはじめたというネタがあったが、まずはそれの顛末から。

第一世代は卵を産んでくれたあとすぐに全滅してしまったが、これは寿命と環境の影響かなと2世代目に期待をかけたのだが、成魚のなったのは十数匹で3世代目を残してまた全滅。3世代目はどうも元気がなく成魚になる前に全滅してしまった。夏の暑さもあったと思うが、ろ過環境であるとかが大げさなのと、水流の影響でメダカの体力が削られてしまったのではないかと推測。

再び稚魚をいただいてきて、今度はろ過のない昆虫用のプラ水槽で、今に至るわけだが、世代を重ねることはなかなかうまくいかないが、元気に泳いでいるのだった。

メダカの水槽の今

ろ過装置付きの水槽が余ったので、昨年から金魚を飼うことにした。せっかくなのでノッタリクッタリ泳ぐのが可愛い琉金一択でホームセンターのペットショップで3匹購入し、飼育開始。そのうち一匹は胸鰭が奇形であまりうまく泳げないようですぐに死んでしまった・・・(購入時によく確認しなかったのがいけなかった)

昔熱帯魚を飼っていたことがあるので、それよりは簡単だろうとなめてかかっていたら、結構繊細な生き物で、冬のある日水替えをしようと、水槽掃除がてらベランダで一晩カルキ抜きをした水に半分ほど替えたことろ、2匹とも水面に浮いてしまい、水底に潜れなくなってしまった。

転覆病というものらしく、すぐに死ぬわけではないが、原因がいろいろあるため治療も困難。予想では急激な水温変化によって内臓疾患を起こしてしまったのではないかと考える。そのような理由であまり長生きが出来なくてかわいそうだった。

そのような理由でしばらく飼うのは控えていたが、先日またホームセンターのペットショップに安い琉金もどき(ミックス金魚売り場)をお迎えして。以前の反省を踏まえて慎重に水替えしながらの飼育を始めた。

しかし数日経って、また転覆病患者が発生(3匹中1匹)。水温は大丈夫なはずだけど、、、。この個体は買ってきたときから非常に元気で餌を与えると大暴れして水面の空気と一緒に餌をパクパク食べまくっていた(俗にいう空気食い)。まさかそれだけで転覆病になるとは思えないけど、餌のやりすぎという面も考えられるので、早期発見ということでしばらく餌を控えたり、ネットの情報を色々な転覆病の治療方法を探してみた。

やはり大方の原因は内臓疾患のようで、消化不良によりお腹の中にガスがたまるためとのこと。よくよく見るとうちの個体も、糞の中に気泡があったり、まさにそういう原因なんだろうなぁという現象だ。

今回の場合は常に転覆しているわけではなく、朝に餌を与えてから暫く転覆症状がおこり、夕方か夜には回復しているためそれほど深刻ではないので、今のうちに試せることをしてみようと、一番簡単そうな対応から始めることとした。

水槽に水草入れて食べさせるのがよいというお話で、以前からお腹の調子をよくするために植物性の餌が良いなどとして、与えてみたがあまり効果がなかったが、水草を食べるように習慣づければ、毎日の餌にガッツくことは少なくなり、転覆現象も改善されるのではと、試してくることとした。

金魚の水草といえばやっぱりカボンバが人気そうなので、さっそく投入。最初は隠れ場くらいにしか使ってないようだったが、しばらくしてみると、新芽がかじり取られていたり、若い葉っぱが減っていたり、最近では一本抜けて浮いているなど、明らかに食べているだろうという状況。

それが確認できるようになったあたりから、転覆症状の時間が短くなってきた。以前は夕方くらいまでお腹を上にして浮いていたのだが、昼過ぎくらいには普通に泳いでいるのが確認できるようになった。

まぁ、転覆病の治療に「水温を上げる」というのがあるので、これから夏場に向けて水温が上がった結果かもしれないが、引き続き様子を見てみたいを思う。

一番右が転覆病患者。口の下が白い琉金タイプなので、「白くちびる」と呼んでいる。

誰も見ていないような独り言ブログなのでとは言わないが、公の場で「生き物を死なせた」ような話をするのは荒れる原因になるかもしれないが、生き物を飼うということはそういうことに向き合っていくことじゃないかなと思います。決して遊び半分ではないし、いつも癒してもらっている分精一杯お世話したいという気持ちになります。

天の川ホタル祭り

昨年に引続き今年もコロナ禍のため中止で残念なので、2018年に行ったときの写真。

どこかの用水路
ゴミ捨て禁止
右手に星空

場所は滋賀県米原市で毎年開催されている感じ。かつてバスツアーで案内されて依頼お気に入りの場所で雨上がりの週末を狙って見に行くことにしている。

実際のホタル祭り会場はもう少し南だが、写真を撮ったのは左の場所。西にグリーンパーク山東というキャンプ場があるので、そこの駐車場に車を停めて、徒歩で目的の場所へ。

天満神社の森の周辺の水田と水路あたりとなる。南の方は民家が多くなるので神社北東あたりが良いかもしれない。

写真はデジカメのオリンパスPEN(EPL-7)で1~3分程度の露光なので、ホタルが凄くたくさん飛んでいるように見えるが、実際は点滅しながら飛んでいるため、点滅の数だけ光点がが増えているという感じ。

撮影方法としては、夜といえどもそんなに暗いところではないため、3分も露光するとホタルよりも周りが明るくなってしまうので、比較明合成という手法を用いている。

数秒露光で数分連続撮影を行い、明るい部分のみの合成を行う。そのため背景は数秒露光分の撮影のまま、光って移動しているホタルだけが明るく写るという仕組みで、星空の公転軌跡の写真などで使われる方法。

通常は連写データをパソコン・フォトショップなどの編集作業による作成するが、オリンパスPENにはそれをカメラ単体で行う機能がある(ライブコンポジット)(右写真)ので上のような写真が比較的簡単に取ることができる。

実はさらに数年前2014年のスーパー雷雨記事の時の写真もこのライブコンポジットの機能をつかってました。さすがに一発撮りであんなにドンピシャな雷写真は撮れないですね。
ライブコンポジット機能で撮影開始して数分待ち、稲妻が走ったら連写ストップ、という撮り方でした。もちろん画角のどこに稲妻が写るのかは運次第。不発もありましたw

djangoチュートリアルメモ

基本的にはdjangoサイトのチュートリアルをそのままトレース。やった事だけをメモしていこうかと。。。

  • 仮想環境への移行 source bin/activate
  • djangoインストール : pip install Django
  • バージョン確認:python -m django –version → 3.2.4
  • プロジェクト作成:django-admin startproject mysite
  • とりあえずテストサーバー起動:python manage.py runserver 0:8000
    外部からアクセスするため(ただしファイヤーウォールで接続制限をかけること)
  • 「Invalid HTTP_HOST header」エラーが出るので、setting.pyを修正
    ALLOWED_HOSTS = [‘*’]
    デフォルトでは空になっているので、自サイト以外からはアクセスできないようだ
  • チュートリアルに沿ってアプリケーション作成
    python manage.py startapp polls
  • ここまで作った状態で、プロジェクト下とライブラリのdjango下をそれぞれgitの管理化に入れて、pythonの勉強を兼ねて、動作の仕組みを解析する予定。

Git小技

gitignore

djangoプロジェクトをcommitするときに、コンパイル済みの*.pycなどあとから「このファイルは対象外にしたいなー」てなったとき。

  • .gitignoreに無視したいファイルを追加
  • すでにコミットしているファイルを対象外(リポジトリから削除)とする
.gitignore:
*.pyc

git管理のトップディレクトリに移動して、git rmで対象削除する

find . -name "*.pyc" -exec git rm -f "{}" \;

Tree表示

git log をきれいにみる方法

ここのサイトを参考に

git log --graph --pretty=format:'%x09%C(auto) %h %Cgreen %ar %Creset%x09by"%C(cyan ul)%an%Creset" %x09%C(auto)%s %d'

下記コマンドにてエイリアス登録

git config --global alias.tree 'log --graph --pretty=format:"%x09%C(auto) %h %Cgreen %ar %Creset%x09by"%C(cyan ul)%an%Creset" %x09%C(auto)%s %d"'

各ユーザーごとホームディレクトリの.gitconfigに追加される。

あとエディタも使い慣れたのにしたいので、

$ git config --global core.editor emacs