오라일리 책을 구입해두고 안보고 있다가 이제야 보니 다른 부분이 너무나도 많아서 문서 보면서 배우기로 급 선회했다. 한글 문서로 먼저 훑어보면 좋을텐데 검색 능력이 부족해서 찾질 못하겠더라. 문서 보면서 대충 날림 번역으로 남겨놨다. 하루면 페이지 다 따라해볼 수 있을 것 같았는데 딴짓하느라 하루에 다 완료를 못해서 파트를 쪼개기로. 주중에 짬짬이 나머지를 보기로 하고 일단 먼저 업로드!

(여기서 뭔가 모자란 부분이나 틀린게 있으면 틀린게 맞으므로 언제든 지적해주시고, 애매한 표현은 원본 문서를 봐주시면 감사하겠습니다. 원본 문서는 SQLAlchemy Tutorial. 한글로 된 sqlalchemy 튜토리얼 있으면 알려주세요!)


SQLAlchemy 객체 관계형 매퍼는 데이터베이스 테이블을 이용해 사용자가 정의한 파이썬 클래스의 메소드와 각각의 행을 나타내는 인스턴스로 표현된다. 객체와 각 연관된 행들의 모든 변경점들이 자동으로 동기되어 인스턴스에 반영되며, 그와 동시에 사용자가 정의한 클래스와 각 클래스 사이에 정의된 관계에 대해 쿼리할 수 있는 (Unit of work이라 하는)시스템을 포함하고 있다.

이 ORM에서 사용하는 SQLAlchemy 표현 언어는 ORM의 구성 방식과도 같다. SQL언어 튜토리얼에서는 직접적인 의견을 배제한 채 데이터베이스들의 초기에 어떻게 구성해 나가야 하는지에 대해 설명하는 반면 ORM은 고수준의, 추상적인 패턴의 사용 방식과 그에 따른 표현 언어를 사용하는 방법을 예로 보여준다.

사용 패턴과 각 표현 언어가 겹쳐지는 동안, 초기와 달리 공통적으로 나타나는 사항에 대해 표면적으로 접근한다. 먼저 사용자가 정의한 도메인 모델서부터 기본적인 저장 모델을 새로 갱신하는 것까지의 모든 과정을 일련의 구조와 데이터로 접근하게 해야한다. 또 다른 접근 방식으로는 문자로 된 스키마와 SQL 표현식이 나타내는 투시도로부터 명쾌하게 구성해, 각 개별적인 데이터베이스를 메시지로 사용할 수 있게 해야 한다.

가장 성공적인 어플리케이션은 각각 독자적인 객체 관계형 매퍼로 구성되야 한다. 특별한 상황에서는, 어플리케이션은 더 특정한 데이터베이스의 상호작용을 필요로 하고 따라서 더 직접적인 표현 언어를 사용할 수 있어야 한다.

(제 실력이 미천해 깔끔하게 번역이 안되네요. 공통된 부분에만 집중하고 각 데이터베이스의 특징을 몰개성화 하며 단순히 저장공간으로 치부하는 다른 ORM과 달리 SQLAlchemy는 각 데이터베이스의 특징도 잘 살려내 만든 ORM이다, 대충 이런 내용입니다. 원문 보세요. ㅠㅠ)


버전 확인하기

import sqlalchemy
print sqlalchemy.__version__

접속하기

이 예시는 메모리서만 사용하는 sqlite 데이터베이스를 사용. create_engine()을 이용해 접속.

from sqlalchemy import create_engine
engine = create_engine('mysql://root:password@localhost/dbname', echo=True)

echo는 로그를 위한 플래그. 파이썬 표준 logging 모듈 사용. 순수 SQL 코드를 보여준다.

engine은 선언만 해서 바로 연결되는게 아니라 첫 실행이 될 때 연결이 됨.

print engine.execute("select 1").scalar()

ORM을 사용할 때는 위처럼 engine을 직접 이용할 필요는 없다. 맨 처음 연결 할 때 작성하고 ORM 사용하면 됨.

매핑 선언

ORM에서는 처음에 데이터베이스 테이블을 써먹을 수 있게 설정한 다음 직접 정의한 클래스에 맵핑을 해야한다. sqlalchemy에서는 두가지가 동시에 이뤄지는데 Declarative 란걸 이용해 클래스를 생성하고 실제 디비 테이블에 연결을 한다.

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

이러면 준비 끝. 이렇게 해두면 몇개고 매핑 클래스를 만들 수 있다. 매핑 클래스 내에서 디비의 컬럼을 나타내는 Column 클래스, 각 컬럼의 데이터타입을 나타내는 IntegerString 클래스를 불러와야한다.

from sqlalchemy import Column, Integer, String

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    fullname = Column(String)
    password = Column(String)

    def __init__(self, name, fullname, password):
        self.name = name
        self.fullname = fullname
        self.password = password

    def __repr__(self):
        return "<User('%s', '%s', '%s')>" % (self.name, self.fullname, self.password)

 User 클래스는 __tablename__에서 정의한 테이블에 맵핑되고 primary key인 id와 name, fullname, password 컬럼을 가진다.

메소드는 마음껏 만들어도 상관없다. 파이썬 기본 class와 똑같음. __init__와 __repr__도 만들어도 되고 안만들어도 된다. Base를 상속하지만 이는 단지 최소의 설정만 담당할 뿐이다.

Declarative system으로 만들어진 이 클래스는 table metadata를 가지게 되는데 이게 사용자정의 클래스와 테이블을 연결해주는 구실을 한다. 예전엔 이 metadata를 만들고 클래스에 맵핑해서 썼는데 그 방식을 Classical Mapping이라고 얘기한다. 그 예전 방식에서는 Table이라는 데이터 구조와 Mapper 객체로 클래스와 맵핑한다. (오라일리에서 나온 sqlalchemy 책에선 이 구방식으로 설명한다 ;ㅅ;)

metadata를 보고 싶다면,

User.__table__

mapper 클래스는,

User.__mapper__

Declarative 기반 클래스는 모든 Table 객체들을 MetaData로 정의해두고 .metadata 속성을 통해 접근할 수 있게 도와준다.

아직 위의 예제 클래스는 테이블이 생성이 되지 않은 상태인데 MetaData를 통해 손쉽게 생성할 수 있도록 도와준다. 테이블을 생성할 때 MetaData.create_all() 로 생성할 수 있는데 이 메소드를 호출하면 Engine으로 연결된 데이터베이스에 테이블을 생성해준다.

Base.metadata.create_all(engine)

최소 테이블 묘사 vs. 완전 상세돋는 묘사

sqlite나 postgresql은 테이블을 생성할 때 varchar 컬럼을 길이를 설정하지 않아도 별 문제 없이 데이터타입으로 쓸 수 있지만 그 외 데이터베이스에서는 허용되지 않는다. 그러므로 컬럼 길이가 필요한 데이터베이스의 경우 length가 필요하다.

Column(String(50))

IntegerNumeric 같은 경우에도 위와 동일하게 쓸 수 있다.

덧붙여 Firebird나 오라클에서는 PK를 생성할 때 sequence가 필요한데 Sequence 생성자를 써야 한다. (auto increment 로 생성되는 뭐 그런류 같은 의미인거같다.)

from sqlalchemy import Sequence
Column(Integer, Sequence('user_id_seq'), primary_key=True)

위에서의 User 클래스를 다시 작성해보면,

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
    name = Column(String(50))
    fullname = Column(String(50))
    password = Column(String(12))

    def __init__(self, name, fullname, password):
        self.name = name
        self.fullname = fullname
        self.password = password

    def __repr__(self):
        return "<User('%s', '%s', '%s')>" % (self.name, self.fullname, self.password)

파이썬 안에서만 쓸꺼라면, 그리고 디비를 밖에서 이미 생성했다면 이전에 작성한 대로만 작성해도 상관 없다.

매핑된 클래스로 인스턴스 만들기

ed_user = User('haruair', 'Edward Kim', '1234')
ed_user.name        # 'haruair'
ed_user.password    # '1234'
str(ed_user.id)     # 'None'

id는 __init__()에서 정의되지 않았지만 맵핑을 해뒀기 때문에 None으로 존재한다. 기본적으로 ORM에서 생성된 클래스 속성들은 테이블에 맵핑된 것으로 표현된다. 이런 클래스 속성들은 descriptors로서 존재하는데 맵핑된 클래스를 위해 instrumentation을 정의해둔다. 이 instrumentaion은 이벤트를 바꾸거나 변경을 추적하거나 자동으로 새로운 데이터를 불러온다거나 할 때 도움을 주는 기능을 한다.

위의 값에서 ‘Edward Kim’을 디비에 넣기 전까진 id는 None이다. 디비에 넣으면 id값은 알아서 들어오게 된다.

세션 만들기

ORM은 데이터베이스를 session을 이용해 다룰 수 있는데 처음 앱을 작성할 때 create_engine()과 같은 레벨에서 Session 클래스를 factory 패턴으로 생성할 수 있다.

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)

모듈레벨에서 작성하고 있어서 Engine이 아직 존재하지 않는다면,

Session = sessionmaker()

이후에 engine을 생성하고 session의 configure를 이용한다.

Session.configure(bind=engine)

위처럼 작성한 Session 클래스는 새 객체를 만들어서 데이터베이스와 연결이 된다. 다른 트랜잭션을 위한 것들은 sessionmaker()에서 호출될 때 정의되야 하는데 자세한건 이후 챕터에서 알려준다고. 이제부터 언제든 데이터베이스와의 대화가 필요할 때 Session을 불러서 쓰면 된다.

session = Session()

위 Session은 Engine과 연결이 되어 있지만 아직 연결이 열린 상태는 아니다. 앞서와 같이 처음으로 사용될 때 Engine과 연결되고 모든 변경을 커밋하고 세션을 종료할 때까지 열려있게 된다.

세션 생성하는 패턴들

Session은 다양한 기반에 다양한 타입의 어플리케이션, 프래임워크에서 다양한 요구사항에서 짱짱 좋다. 그러니까 Session은 오브젝트와 일반적인 데이터베이스 접속에서 쓰면 된다. 어플리케이션 스레드를 저녁 만찬이라 생각하면, 세션은 손님의 접시이고 객체는 놓여질 음식이라 볼 수 있다. (디비는 주방쯤?) 세션을 어떻게 써야할지 고민한다면 다음 링크 참조.

새 객체 추가하기

ed_user= User('haruair', 'Edward Kim', '1234')
session.add(ed_user)

여기선 실제로 데이터베이스에 추가된게 아니라 pending인 상태다. 아직 데이터베이스에 발행되지는 않은 상태인데 입력이 필요한 순간에는 flush라는 과정을 통해 입력이 된다. 만약 디비에 쿼리를 하면 모든 pending 된 정보는 flush되고 접근 가능한 상태가 된다. (실제로 저장된 상태는 아님. 여전히 pending.)

예를 들면 아래 코드는 User 인스턴스를 로드해 새 Query 객체를 생성한다.

our_user = session.query(User).filter_by(name='haruair').first()
our_user     # <User('haruair', 'Edward Kim', 'secret')>

사실 Session은 내부적으로 맵구조의 객체라 반환하는 값이 우리가 기존에 집어넣은 인스턴스랑 동일하다.

ed_user is our_user     # True

ORM의 컨셉이 identity map이라서 session에서 하는 모든 처리들이 실제 데이터셋과 함께 동작한다. Session에서 PK를 가지면 PK 가진 같은 파이썬 객체를 반환한다. 그러니까 이미 있는 PK를 입력하면 에러가 난다.

add_all()로 한방에 추가할 수도 있다.

session.add_all([
    User('wendy', 'Wendy Williams', 'foobar'),
    User('mary', 'Mary Contrary', 'xxg527'),
    User('fred', 'Fred Flinstone', 'blar')])

비밀번호를 함 바꿔보자.

ed_user.password = 'test1234'

Session은 계속 연결되어있는 객체를 계속 주시하고 있다. 위처럼 수정하면 session은 이미 알고있다.

session.dirty        # IdentitySet([<User('Edward', 'Edward Kim', 'test1234')>])

새로 추가한 애들도 볼 수 있다.

session.new
# IdentitySet([<User('mary', 'Mary Contrary', 'xxg527')>,
#              <User('wendy', 'Wendy Williams', 'foobar')>,
#              <User('fred', 'Fred Flinstone', 'blar')>])

Session에 pending된 애들을 실행시키려면,

session.commit()

commit()은 모든 변경, 추가 이력을 반영한다. 이 트랜잭션이 모두 실행되면 세션은 다시 connection pool을 반환하고 물려있던 모든 객체들을 업데이트 한다. 실제 데이터베이스에 삽입함.

암튼, 앞서 id가 ‘None’ 이었던 녀석을 다시 보면,

ed_user.id    # 1

Session이 새 행을 데이터베이스에 입력한 이후에 새로 생성된 행들은 식별자들과 데이터베이스에서 기본으로 설정된 값들을 instance에서 사용할 수 있게 된다. 즉시 사용할 수 있거나 첫 액세스에 로딩될 때 모두 사용할 수 있다. 위 경우엔 commit()을 실행한 이후 새 트랜잭션이 실행되어 모든 행이 다시 로드된 상태다.

sqlalchemy에서는 기본적으로 이전 트랜잭션에서 새 트랜잭션으로 처음 실행될 때 모든 데이터를 새로 가져온다. 그래서 가장 최근의 상태를 바로 사용할 수 있다. 다시 불러오는 레벨을 설정하고 싶으면세션 사용하기 문서를 확인하자.

세션 객체의 상태들

User 객체가 Session 외부에서 PK 없이 Session 안에 들어가고 실제로 데이터베이스에 추가될 때 까지 각 “객체 상태” 를 가지고 있다. transient, pending, persistent 세가지. 이 상태들을 알고 있으면 도움이 되므로 객체 상태에 대한 설명을 잽싸게 읽어보자.

롤백하기

Session이 트랜잭션으로 동작하고 나서 우린 롤백 하는 것도 가능하다. 롤백해보기 위해 값을 변경해보자.

ed_user.name = 'edkim'

그리고 가짜 유저를 하나 생성한다.

fake_user = User('fakeuser', 'Invalid', '12345')
session.add(fake_user)

Session을 query하면 일단 flush된 현재의 트랜잭션을 확인할 수 있다.

session.query(User).filter(User.name.in_(['edkim', 'fakeuser'])).all()
#[<User('edkim', 'Edward Kim', 'test1234')>, <User('fakeuser', 'Invalid', '12345')>]

롤백을 실행하면 변경하기 전 상태로 돌아간다.

session.rollback()
ed_user.name            # 'haruair'
fake_user in session    # False

쿼리 보내기

Query 객체는 session에서 query() 메소드로 생성한다. 이 함수는 다양한 수의 아규먼트를 가질 수 있는데 다양한 클래스의 조합과 클래스 descriptor를 사용할 수 있다. 사실 Query는 User 인스턴스를 부를 때 이미 써봤다. iterative context를 evaluated할 때, User 객체 리스트를 반환한다.

for instance in session.query(User).order_by(User.id):
    print instance.name, instance.fullname

Query는 KeyedTuple 클래스 통해 튜플로 반환하는데 일반적인 파이썬 객체처럼 활용할 수 있다. 각 저장된 값들은 클래스 이름이나 속성 이름과 동일하다.

for row in session.query(User, User.name).all():
    print row.User, row.name

label()을 이용하면 컬럼 이름을 다르게 쓸 수 있다. 어떤 클래스 속성이든 매핑해서 쓸 수 있다.ColumnElement-derived object.

for row in session.query(User.name.label('name_label')).all():
    print row.name_label

컬럼은 위 방식으로 하지만 User 같은 클래스 엔티티는 aliased를 이용해 제어할 수 있다.

from sqlalchemy.orm import aliased
user_alias = aliased(User, name='user_alias')
for row in session.query(user_alias, user_alias.name).all():
    print row.user_alias

LIMIT이나 OFFSET을 포함한 기본적인 Query 동작은 order by와 함께 파이썬 배열에서 쪼개는(slice) 방식처럼 쓰면 된다.

for user in session.query(User).order_by(User.id)[1:3]:
    print user

결과물을 filter 할 때에는 filter_by()를 쓰면 된다.

for name in session.query(User.name).filter_by(fullname='Edward Kim'):
    print name

또는 filter()를 쓰면 되는데 좀더 유연한 SQL 표현을 쓸 수 있다. 매핑클래스에서 사용한 클래스 단위의 속성과 파이썬 표준 연산자를 쓸 수 있다.

for name in session.query(User.name).filter(User.fullname=='Edward Kim'):
    print name

Query 객체는 완전 생산적이라 대부분의 메소드 호출은 새 Query 객체를 반환한다. 따라서 아래와 같이 꼬리를 무는 체이닝 방식으로 사용이 가능하다. (Where … And … 식으로 된다.)

for name in session.query(User).\
            filter(User.name=='haruair').\
            filter(User.fullname=='Edward Kim'):
    print user

일반 필터(filter) 연산자들

equals

query.filter(User.name == 'ed')

not equals

query.filter(User.name != 'ed')

LIKE

query.filter(User.name.like('%ed%'))

IN

query.filter(User.name.in_(['ed', 'wendy', 'jack']))

서브쿼리식으로도 됨

query.filter(User.name.in_(session.query(User.name).filter(User.name.like('%ed%'))))

NOT IN

query.filter(~User.name.in_(['ed', 'wendy', 'jack']))

IS NULL

filter(User.name == None)

IS NOT NULL

filter(User.name != None)

AND

from sqlalchemy import and_
filter(and_(User.name == 'ed', User.fillname == 'Edward Kim'))

또는 위에서 본 체이닝 메소드로

filter(User.name == 'ed').filter(User.fullname == 'Edward Kim')

OR

from sqlalchemy import or_
filter(or_(User.name == 'ed', User.name == 'wendy'))

match

매치 파라미터는 백엔드에서 특정된다.. (무슨 말인지 잘;)

query.filter(User.name.match('wendy'))

출처 : http://haruair.com/blog/1682

'공부 > Python' 카테고리의 다른 글

Dropbox API 사용하기 (with python)  (0) 2013.08.16
SQLAlchemy Tutorial(한글) - 2  (0) 2013.08.14

apt-get install netatalk

nano /etc/netatalk/afpd.conf


add this line

- -tcp -noddp -uamlist uams_dhx.so,uams_dhx2_passwd.so -nosavepassword -setuplog "default log_info /var/log/afpd.log"


nano /etc/netatalk/AppleVolumes.default

~/                      "Home Directory"

=>

~/                      "$u@$h"

service netatalk restart

cocos2d-x 에서 레이어를 통해 게임 화면을 구성합니다.


이미지 출처 : http://www.learn-cocos2d.com


이런식으로 말이죠. 레이어를 풀스크린으로 쓰면 상관이 없지만 간혹 특정 크기에 맞춰야 할때가 있습니다. 화면을 분할하여 좌측, 우측 레이어를 구분해서 사용한다던가 할때 말이죠. cocos2d-x의 Layer 클래스는 상위 Node 클래스를 상속 받기 때문에 setContentSize 인터페이스를 사용할 수 있습니다.


하지만 이 인터페이스를 통해 크기를 조절한다 해도 실제 화면에서 보면 아무런 변화가 없습니다.


아래의 그림은 960 x 640 해상도에서 집과 캐릭터를 메인 레이어에 출력한 화면입니다. 이 메인 레이어 사이즈는 가로 해상도의 반인 480 x 640으로 설정해준 상태입니다(하늘 배경은 백그라운드 레이어 ).



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool CGameScene::InitLayer( void )
{
    bool bRet = false;
    do
    {
        // super init first
        CC_BREAK_IF( !CCScene::init() );
 
        // 배경 레이어
        CGameSceneBGLayer* pBGLayer = CGameSceneBGLayer::create();
        CC_BREAK_IF( !pBGLayer );
        this->addChild( pBGLayer, 0, CHILD_LAYER_BACKGROUND );
 
        // 메인 레이어
        CGameSceneMainayer* pMainLayer = CGameSceneMainLayer::create();
        CC_BREAK_IF( !pMainLayer );
        pMainLayer->setContentSize( CCSizeMake( 480, 640 ) );
        this->addChild( pMainLayer, 0.5, CHILD_LAYER_MAIN );
 
        bRet = true;
    } while (0);
 
    return bRet;
}

하지만 실제 화면은 960 x 640 풀 사이즈로 나오고 있습니다. 가로 사이즈 480으로 설정한대로라면 오른쪽에 있는 집, 대머리 캐릭터는 짤려야 정상인데 말이죠. 레이어가 설정해준 480 x 640의 크기로 출력되게 하려면 Layer 클래스를 상속 받아 visit 함수를 아래와 같이 재정의 해주어야합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
void CClippingLayer::visit()
{
    glPushMatrix();
    glEnable( GL_SCISSOR_TEST );
 
    CCSize contentSize = getContentSize();
    CCEGLView::sharedOpenGLView()->setScissorInPoints( getPosition().x, getPosition().y,
        contentSize.width, contentSize.height );
 
    CCNode::visit();
 
    glDisable( GL_SCISSOR_TEST );
    glPopMatrix();
}

이 후 메인레이어를 새로 정의한 CClippingLayer를 상속 받아 사용하면...



이제 원했던대로 메인 레이어가 반만 출력됩니다.



출처 : http://kindtis.tistory.com/489

필요 사항

OS : OSX 10.7 이상 Lion


시작 합니다. ~


1. http://developer.android.com 에서 Download 항목을 클릭 합니다.



2. NDK 항목을 선택하고, 오른쪽에서 Mac OS X 항목을 클릭 하여 자료를 다운받습니다.


3. 받은 자료를 적당한 곳에 압축을 풀어 둡니다.


4. 터미널을 열어서 자신의 홈디렉토리에 .bash_profile 이 있는지 확인합니다.

( ls -al 명령을 치면 리스트가 나옵니다. 저는 없네요^^)



5. 있든 없든 일단 vi .bash_profile 이라고 입력합니다.


6. 편집 화면이 나오는데 빈화면인 사람은 ~ 표시들만 있고 빈화면 일 테고, 파일이 존재하는 사람은 export PATH=${PATH}:블라블라:블라블라 라고 되어 있을 겁니다.

(기본 vi 입력 방법 - i키를 누르면 입력을 하실 수 있습니다. 입력을 다 하셨으면 esc 키를 눌러 입력을 끝을 냅니다. :wq 를 입력하면 (w:write , q:quit) 저장하고 밖으로 나가실 수 있습니다.)

6.1 화면에 아무것도 없다면, export 부터 끝까지 다 쳐줍니다. 

기본은 export PATH:${PATH}: 여기까지 입니다. 그 뒤는 아까 다운로드 받은 ndk의 주소입니다. 

아래는 제 NDK가 설치되어 있는 주소입니다.

6.2 화면에 export  가 있으신 분은 맨 뒤에 :/ndk 주소/를 넣어주시면 되겠습니다.


7. 이제 ls -al 명령으로 제대로 만들어졌는지 확인을 해봅시다. 저는 잘 생성되었네요~



8. 이제 적용을 해봅시다. source .bash_profile 을 입력하여 path가 적용되도록 합시다.



9. 이제 완성입니다. ndk-build 를 입력하여 어느 곳에서나 잘 동작하는지 확인해봅니다.


출처 : http://blog.naver.com/hello20/150136506664


XE 코어 백업과 복원하기

XE의 백업과 복원은 포장이사로...

XE 코어로 만든 웹사이트를 업그레이드하거나 다른 서버로 이사를 가야 할 때 백업과 복원은 필수입니다. 그런데 FTP 프로그램을 이용해 파일을 하나하나 내려받고 다시 서버에 올린다면 XE 코어는 정상적으로 작동하지 않습니다. 왜냐하면 여러분이 호스팅 서비스를 이용해 계정을 할당 받고 사용하게 되면 아래 그림과 같이 html이라는 사용자 폴더(root, 서버환경에 따라 public_html 또는 www라는 폴더를 사용)를 이용하게 되는데 이 폴더 안에는 여러분이 사용중인 폴더와 XE 코어가 만들어서 사용하는 files 디렉터리가 함께 있기 때문입니다. files 디렉터리는 xe 디렉터리 안에 있고 웹사이트의 운영내용 및 설정 파일들을 XE 코어가 수시로 점검하고 수정하고 첨부 파일들을 저장하는데 사용하고 있습니다. 이 files 디렉터리는 FTP를 이용해 다운로드 하거나 이동, 복사 할 수 없습니다.

웹사이트 운영시 함께 할당 받는 또 하나는 데이터베이스(DB)입니다. DB는 쉽게 말해 엑셀문서를 닮았다고 설명드린 적이 있습니다. 데이터 하나하나를 쪼개어 저장하는 아주 강력한 친구입니다. 하지만 무척 까탈스러운 친구라 말붙이기도 어렵고 접근하기 조차 쉽지 않습니다. 하지만 XE 코어를 도와 항상 열심히 일하는 아주 근면성실한 친구이기 때문에 믿음직스럽습니다.

image

웹사이트를 백업한다는 것은 보통 html 폴더(root) 전체를 하나의 파일로 묶는 것을 말하는데 반드시 잊지말아야 하는 것은 DB에 저장되어 있는 자료 역시 압축파일로 받아 두어야 합니다. 만약 DB를 백업 받아두고 다시 복원해 주지 않으면 XE 코어는 정상적으로 작동하지 않습니다. 따라서 계정의 백업은 디렉터리의 백업과 DB 백업으로 나누어 작업하게 됩니다. XE 코어와 DB의 상호작용은 관리자 페이지에 있는 캐시파일 재생성 버튼으로 연동을 유지하게 됩니다. 이렇게 XE 코어를 백업 받거나 복원하기 위해서는 반드시 포장을 잘 해 두어야하며 또는 부득이하게 다른 서버 계정으로 이사를 가야한다면 반드시 포장이사를 맡겨야 합니다...^^ (필요에 따라서는 XE 디렉터리만 포장해도 상관 없으며 index.html 문서는 별도로 작성하고 필요한 파일만 가져가도 됩니다.)


1. 파일 및 디렉터리의 백업과 복원

계정의 백업 작업은 FTP를 이용해서 할 수 없습니다. 오직 SSH 또는 Putty 프로그램을 이용해 서버에 접속하고 텔넷 명령어를 사용해서 백업 및 복원 명령어를 입력해야 합니다. SSH를 이용해 서버에 접속하게 되면 최상위 디렉터리 바깥에서 디렉터리 전체를 하나의 파일로 묶어주는 명령어를 입력합니다. 최상위 디렉터리(root)는 서버 환경에 따라서 html, www 또는 public_html로 사용할 수 있습니다. ls 명령어를 입력해 보고 html, www, public_html 디렉터리만 보인다면 루트 디렉터리 바깥에 있는 것이 맞습니다.

tar -cvfpz backuphtml.tar.gz html

html은 압축하고자 하는 디렉터리의 이름이고 backuphtml.tar.gz는 백업 작업의 결과로 만들어질 압축파일 이름입니다. tar의 옵션의 c는 파일 및 디렉터리를 하나로 묶어 새 저장 파일을 만들라는 뜻입니다.

이렇게 만들어진 backuphtml.tar.gz 압축파일은 루트 디렉터리 바깥에 있고 서버에 그대로 두어도 상관은 없지만(서버용량이 가능하다면) 추후에 작업을 위해서는 FTP 프로그램을 이용해 다운로드 받아 두는 것이 좋습니다. 그리고 압축파일 네이밍을 할 때 백업일자를 같이 써주면 언제 백업 받아둔 것이지 쉽게 확인할 수도 있겠지요. 예) backuphtml_20110630.tar.gz

디렉터리의 백업파일을 복원하는 것은 마찬가지로 루트 디렉터리 바깥에서 아래의 명령어를 입력하는 것으로 쉽게 작업하실 수 있습니다. 이번에는 옵션에 c가 아니라 압축을 해제하는 옵션 x를 주게 됩니다. 만약 다른 계정에서 해제하려면 FTP를 이용해 백업 받은 압축 파일을 미리 업로드 해 두어야 합니다.

tar -xvfpz backuphtml.tar.gz

압축이 풀리게 되면 자동으로 html 디렉터리 안에 모든 파일이 원상태로 복구됩니다. 만약 다른 계정에서 html 디렉터리가 없다면 html 디렉터리를 만들고 압축된 파일을 그 안에 풀어 놓게 되는데 이때 html 디렉터리 안의 모든 내용을 새로운 계정 환경의 루트(root) 디렉터리 안으로 옮겨 주어야 합니다.(※ 아래 "다른 서버 계정으로 이사가기" 참고) 옵션 -p는 모든 퍼미션(권한) 정보를 포함하여 압축을 하기도 하고 해제하기도 하지만 만약을 위해 chmod 707 xe 명령을 실행하여 xe 디렉터리의 권한설정을 다시한번 실행해 주어도 좋습니다.

chmod 707 xe

TIP - 간혹 xe 디렉터리 안에 xe가 만들고 사용하는 files 디렉터리의 권한 문제로 오류가 발생하기도 합니다.
이런 경우 chmod -R 707 xe/files 명령어로 files 디렉터리를 포함하여 하위 폴더까지 권한을 재설정해 줍니다. 기타 오류에 대해서는 이용중인 호스팅 웹서버의 root 권한이 필요한 경우가 있습니다. 이런 경우 서비스 제공 회사와 상의하는 것이 바람직합니다.


2. 데이터베이스(DB)의 백업과 복원

DB의 백업은 파일을 압축하는 방법이 아니라 DB에서 사용할 수 있는 sql 문서를 한장 만들어 받아 두는 것입니다. DB는 까탈스러운 친구라고 했죠? 자료를 좀 백업해 달라고 요청을 하면 달랑 서류 한장만 넘겨 줍니다...^^ 그런데 이것을 압축 파일이라고도 부르는 이유는 모든 내용을 텍스트로만 작성하기 때문에 압축한다는 의미로 표현하는 것입니다. CD를 굽는다고 표현하는 것과 같습니다. 이 문서는 나중에 복원을 할때도 DB에게 보여주기만 하면 된답니다. DB를 백업하는 명령어는 아래와 같습니다.

mysqldump -u 아이디 -p 디비네임 > backupdb.sql

DB의 본래 이름은 데이터베이스 관리 시스템(Database Management System, DBMS)인데 이 친구가 쓰는 말은 SQL(Structured Query Language, 구조화 질의어)이라는 언어를 씁니다. 좀 유별납니다...^^ 그래서 정중하게 mysql님 DB를 좀 출력(dump)해 주시죠!(dump is a Unix program used to backup file systems.) 라고 해야 합니다. 명령어가 아닌 정중한 부탁을 해야 합니다. 그러면 backupdb.sql 문서를 내놓습니다. 이 문서 안에는 XE 코어에서 사용하는 테이블의 종류와 갯수 및 내용(스키마), 그리고 그동안 누가 로그인해서 어떤 글들을 썼는지, 그리고 어떤 첨부파일이 어느 디렉터리에 보관되고 있었고, 레이아웃은 어떤 것을 자주 쓰는지, 메뉴는 어떤 것들이 있는지 하는 아주 소소한 것들까지 적어 놓은 가계부와 같습니다.

DB를 복원하려면 위에서 받아둔 sql 문서를 다시 DB에게 보여주기만 하면 됩니다. 이때는 화살표를 반대로 꺽어주면 되죠!

mysql -u 아이디 -p 디비네임 < backupdb.sql

출력(dump) 해 달라는 부탁은 할 필요없습니다. 화살표만 mysql 쪽으로 꺽어서 sql 문서를 보여주기만 하면 됩니다. -p 다음에 비밀번호가 없는 것은 나중에 password: 라고 입력을 기다리기 때문에 그때 입력하면 됩니다. 아이디와 디비네임은 여러분의 계정 아이디와 DB의 네임을 입력하시면 됩니다.(서버에 따라 계정의 아이디와 DB네임, 비밀번호가 다를 수 있습니다.)

TIP - 아이디와 옵션 -u는 붙여 쓰기도 합니다. 즉 옵션 -u 다음의 문자열은 DB의 아이디로 인식합니다.


캐시파일 재생성 하기

루트 디렉터리와 그 안의 모든 파일들을 백업하고 DB 역시 백업한 후에 다시 복원 작업을 거치게 되면 반드시 XE 관리자로 로그인 한 후에 캐시파일을 재생성 해 주어야 합니다. 만약 관리자로 로그인이 되지 않는 경우, 하얀 백지로 웹사이트가 표시 된다면 xe/files/cache 디렉터리를 삭제(rm -rf cache)한 후에 아래 관리자 주소를 웹브라우저 주소 입력칸에 직접 입력하여 관리자로 로그인 합니다. /xe/는 코어 설치폴더 이름입니다.

  • http://웹사이트 주소/xe/?module=admin
  • http://웹사이트 주소/xe/?module=admin&act=dispAdminConfig

관리자 로그인 후 캐시파일을 재생성하게 되면 XE 코어가 정상적으로 작동하게 됩니다.

TIP - 텔넷 명령어 rm -rf cache 로도 xe/files/cache 디렉터리가 삭제되지 않으면 nobody 권한문제 때문입니다. 호스팅 회사에 문의하여 삭제를 요청하는 것이 좋습니다. 간혹 php 문서를 활용한 권한수정도 통하지 않는 경우가 있습니다. 이런 경우 SuperUser 권한으로 nobody권한을 다시 조정해 줘야 합니다.


다른 서버 계정으로 이사가기

위의 과정은 같은 서버의 계정에서 필요에 따라 계정을 백업하거나 복원할 때 사용하는 방법입니다. 그럼 다른 서버의 계정으로 이사를 가야 한다면 어떻게 할까요?

image

백업된 디렉터리 압축파일과 DB에게서 받아 두었던 sql 문서를 복원하는 방법은 위와 동일합니다. 다만, 새로운 서버의 설정값들이 변경되기 때문에 이에 따른 수정할 부분이 추가됩니다. 우선 최상위 디렉터리(root)의 이름이 html이 아니라고 한다면 FTP로 업로드한 후 압축을 풀었을 때 html 디렉터리 안에 모든 파일과 폴더가 풀어져 있습니다. 이것을 새로 이사 간 서버의 루트 디렉터리(public_html 또는 www) 안으로 옮겨 주어야 합니다. 이때 사용하는 명령어는 아래와 같습니다.

mv html/* public_html

html 안의 모든(*) 파일과 폴더를 public_html 디렉터리 안으로 이동하라!(move) 는 뜻입니다. 완료가 되면 FTP를 이용해서 xe 디렉터리 안에 .htaccess 파일이 제대로 있는지도 확인해 보시고 재 확인차 chmod 707 xe 명령을 이용해 권한설정을 한번 더 확인해 줍니다.

TIP 1 - 리눅스 명령어 mv 에서 와일드카드(*)를 사용하면 도트(.)로 시작되는 파일이름(숨김파일)을 포함하도록 확장되지 않습니다. 이런경우 [mv 디렉터리/* 이동할 디렉터리] 와 [mv 디렉터리/.htaccess 이동할 디렉터리] 이렇게 2번 나누어서 실행하거나 또는 [mv 디렉터리/{*,.htaccess} 이동할 디렉터리/]처럼 여러 대상을 포함시켜 이동할 수 있습니다. 아래 예제와 같이 명령어를 실행하면 .htaccess 파일도 함께 이동할 수 있습니다.
예제) mv html/{*,.htaccess} public_html/
또는 mv html/{*,.*} public_html/ 도 같은 역할이지만 서버환경 옵션설정에 따라 허용되지 않을 수 있습니다.
숨김파일은 ls -a 옵션을 사용하여 확인할 수 있습니다.

TIP 2 - 숨김파일까지 한꺼번에 이동하려면 shopt -s dotglob 명령어를 우선 실행한후 mv 명령어를 이용해 와일드카드(*)를 사용하면 한번에 이동이 가능합니다.
shopt -s dotglob
mv html/* public_html/

그리고 다른 서버로 이사를 간 경우에는 XE 코어가 이전 서버에서 사용했던 xe/files/cache 디렉터리가 더이상 필요없습니다. 새로운 설정값을 다시 만들어야 하기 때문에 rm -rf cache 명령을 이용해 cache 디렉터리를 완전히 삭제해야 합니다.

★중요★
새로운 서버의 아이디와 DB네임으로 DB를 복원한 후에는 반드시 /xe/files/config/db.config.php 문서를 FTP를 이용해 서버에서 내려받고 그 안에 적힌 이전 서버의 내용을 새로운 서버의 아이디와 비밀번호, DB네임, 사이트 주소 등을 수정하여 XE 코어에게 이곳은 새로운 서버라는 것을 알려 주세요. 만약 아래 내용처럼 수정을 하여 업로드 한 후에도 문제가 발생하게 되면 설정 중에 localhost 등과 같이 기타 서버에서 사용하는 설정 방법을 호스팅사에 문의하여 수정해야 합니다.

db.config.php 파일 수정 :

<?php if(!defined("__ZBXE__")) exit();
$db_info->master_db = array('db_type' => 'mysql','db_port' => '3306','db_hostname' => 'localhost','db_userid' => 'DB아이디','db_password' => 'DB비밀번호','db_database' => 'DB이름','db_table_prefix' => 'xe_');
$db_info->slave_db = array(array('db_type' => 'mysql','db_port' => '3306','db_hostname' => 'localhost','db_userid' => 'DB아이디','db_password' => 'DB비밀번호','db_database' => 'DB이름','db_table_prefix' => 'xe_'));
$db_info->default_url = 'http://홈페이지 URL/xe/';
$db_info->lang_type = 'ko';
$db_info->use_rewrite = 'Y';
$db_info->time_zone = '+0900';
?>
  • 'db_hostname' => 'localhost'
  • 'db_userid' => 'DB아이디'
  • 'db_password' => 'DB비밀번호'
  • 'db_database' => 'DB이름'

db.config.php 파일을 수정한 후 다시 업로드하여 원본 파일을 덮어씌운 후에 관리자로 로그인하게 되면 반드시 캐시파일을 재생성하여 변경된 서버 계정의 환경 설정값들을 새로운 캐시파일로 생성하도록 하고 XE 코어와 DB가 연동하게 되면 XE 포장이사는 무사히 마치게 됩니다. 만약 /xe/files/cache 디렉터리가 rm -rf 명령어로도 삭제되지 않는다면 호스팅 회사에 문의하여 삭제를 요청하시면 곧바로 삭제를 해 줍니다.


포장이사 도움말

XE 코어의 백업과 복원, 서버 계정의 이전은 그리 쉬운 작업은 분명히 아닙니다. 왜냐하면 같은 계정 안에서의 백업 및 복원작업은 상대적으로 문제가 적은 반면에 다른 서버의 계정으로 이사를 가는 것은, 이사라는 일이 늘 그렇듯 그릇이 깨지기도 하고 가구에 스크레치가 나기도 하는 등 새로운 문제점들이 늘 발생할 수 있습니다. 새로운 서버의 설정과 운영에 따라 문제가 발생된 경우에는 호스팅사의 도움을 요청하는 것이 바람직합니다.

★ 무작정 XE를 백업 받고 새로운 서버로 이사를 가기보다는 호스팅 회사에 문의를 하여 백업 받은 XE 코어를 복원할 수 있는지에 대한 여부와 환경 설정에 필요한 자문을 구하는 것이 바람직합니다. 일반적인 경우 호스팅 서비스 회사는 이에 대한 안내를 자세히 해주며 백업파일이 있는 경우 호스팅 회사가 무료로 직접 압축파일을 해제하고 복원 해 주기도 합니다.

일반적인 문제발생의 원인은 이전 서버에서 파일 및 폴더을 압축할 때 nobody 권한에 따른 설정들이 새로운 서버에서 제대로 적용되지 않기 때문에 작은 문제들이 발생 되곤 한답니다.(호스팅 회사의 안내) 따라서 XE 코어 운영에 최적화된 좋은 호스팅 서비스 회사를 선택하고 XE 코어의 백업 파일을 제대로 포장한 후에 서버 이전을 진행하는 것이 가장 확실한 방법임을 추천합니다.
(※ 위와 같은 기본적인 텔넷 명령어들이 받아들여지지 않는 서버 계정은 추천하지 않습니다.)



출처 : http://www.xeschool.com/xe/step1_52

요즘 스마트폰의 데이터 쓸수 있는 양이 많아져서 효용이 있을지 모르겠지만..

한번 정리하는 마음으로 기록 해 봅니다.

"Connectify Hotspot"이란 유틸리티도 있습니다만.... 상용이라서...

 

노트북의 유선은 연결 되어 있고, 무선 랜카드가 있는 상태에서 스마트폰으로 인터넷을 3G가 아닌

노트북의 무선랜 -> 유선 -> 인터넷을 사용 하는 방법이 되겠네요..

 

 

준비물: 유선으로 인터넷이 연결된 노트북, 무선 랜카드(호스트된 네트워크 지원 되어야 함), 스마트폰

 

관리자 권한으로 cmd 창을 열어놓고 다음 붉은색 배경의 명령어는 cmd 창에서 입력 합니다. 

 

1. 무선 네트웍 카드가 무선 AP로 만들 수 있는지 확인 

netsh wlan show drivers

  => 호스트된 네트워크 지원  : 예


2. 무선 AP로 만들기: SSID, Key는 임의 값 입력

netsh wlan set hostednetwork mode=allow ssid=AdhocTest key=testtest

netsh wlan start hostednetwork


3. 이더넷 공유

네트웍 등록 정보 > 이더넷 > 속성 > 공유 > 인터넷 연결 공유 > 홈 네트워킹 연결에 신규로 생성된 인터페이스 선택 (Wi-Fi 2)


4. 스마트폰으로 접속

SSID=AdhocTest

암호=testtest


5. 노트북에서 연결 된 내역 확인

netsh wlan show hostednetwork


<<명령어 실행 전의 네트워크 연결 정보>>


<<1. 무선 네트웍 카드가 무선 AP로 만들 수 있는지 확인 >>

 

<<2. 무선 AP로 만들기: SSID, Key는 임의 값 입력>>

 

 

<<네트웍에 Wi-Fi 2 인터페이스 생성>>연결 상태가 네트웍크에 연결 되어 있지 않음

 

 



<<3. 이더넷 공유>>


<<이더넷 공유 후 Wi-Fi 2의 연결이 인터넷 엑세스 상태>>


<<5. 노트북에서 연결 된 내역 확인>>


출처 : http://blog.naver.com/e1seung/110172460781


'Storage > 정보' 카테고리의 다른 글

부트스트랩 테마  (0) 2013.07.19

사용자를 추가하기 위해서는 반드시 루트 계정이 있어야 한다.

1. grant all privileges on *.* to 'testuser'@'localhost'

   identified by '설정패스워스' with grant option;

2. grant all privileges on *.* to 'testuser'@'%'

   identified by '설정패스워스' with grant option;

3. grant reload,process on *.* to 'testuser'@'locahost';

4. grant usage on *.* to 'testuser'@'locahost';

1번과 2번의 경우는 슈퍼 계정!! root와 같은 모든 권한을 가지는 계정을 가지게 된다.

1번 계정은 로컬호스트에서 접속을 할 경우에만 사용되는것이고,

2번 계정은 다른 호스트에서 접속을 하기 위해 사용된다.

testuser란 계정으로 어디에서든지 접속을 하려면 testuser이름으로 1,2번 계정을 모두 가지고 있는 것이 필요하다.

3번 계정은 패스워드가 정의되어있지 않다.

이것은 로컬호스트에서 reload와 process관리 권한을 가지고있다.

mysqladmin reload,mysqladmin refresh, mysqladmin flush-xxx, mysqladmin processlist 도 실행할수 있다고 한다. 하지만 어떤 데이터 베이스에도 접급할수있는 권한은 없다!

나중에 grant명령문을 입력하새ㅓ 권한을 추가할수도 있다.

4번 계정은 3번가 마찬가지 이지만 아무런 권한이 없는 계정을 만든것이다.

USAGE가 그런 뜻을 의미하는데, 이것은 모든 글로번 권한을  'N'으로 설정한 것이라고 한다.

이계정에 특정 권한을 나중에 승인할 것이라는 가정을 한다.

계정을 생성하는 또 한가지 방법은 INSERT 문을 사용하는 것이다.

1. insert into user values('locahost','계정명',password('패스워드'),

   'y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y');

2. insert into user values('%','계정명',password('패스워드'),

   'y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y');

3. insert into user set Host='locahost',User='계정명',Reload_priv='y',Process_priv='y';

4. insert into user(Host,User,Password) values('locahost','계정명','');

5. flush privileges;

1,2,3,4번 계정의 의미는 위에서 grant를 이용하여 만든 계정과 의미가 같다.

5번의 flush privileges; 는 서버가 grant 테이블을 다시 읽어 오도록 만들기 위해서 이다.

그렇지 않으면 서버를 재 구동 시키기 전에는 변경 사항이 적용되지 않는다.

하지만 grant를 사용하는 경우는 flush pricileges가 필요 없다.

1,2번의 insert문의 패스워드 입력에서 password('패스워드')라고 사용한것은 패스워드를 암호화 하기 위해서 이다. grant명령문은 알아서 암호화가 된다!

이번에는 데이터베이스 접근 권한을 설정해보자.

1. grant select, insert, update, delete, create, drop

   on bankaccount.*

   to 'custom'@'localhost'

   identified by 'obscure';

2. grant select, insert, update, delete, create, drop

   on expenses.*

   to 'custom'@'whitehouse.gov'

   identified by 'obscure';

3. grant select, insert, update, delete, create, drop

   on customer.*

   to 'custom'@'server.domain'

   identified by 'obscure';

1번 계정은 bankaccount 데이터 베이스에 접근할 수는 있으나, 로컬 호스트에서만 가능하다.

2번 계정은 expenses 데이터 베이스에 접근할 수 있으나, 호스트 whitehouse.gov에서만 가능하다.

3번 계정은 customer 데이터 베이스에 접근할 수 있으나, server.domain에서만 가능하다.

insert를 사용한 방법.

1-1. insert into user(Host,User,Password) values('locahost','custom',password('obscure'));

1-2. insert into user(Host,User,Password) values('whitehouse.gov','custom',password('obscure'));

1-3. insert into user(Host,User,Password) values('server.domain','custom',password('obscure'));

2-1. insert into db

     (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_pric,Create_pric,Drop_pric)

     values('localhost','bankaccount','custom','y','y','y','y','y','y');

2-2. insert into db

     (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_pric,Create_pric,Drop_pric)

     values('whitehouse.goc','expenses','custom','y','y','y','y','y','y');

2-3. insert into db

     (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_pric,Create_pric,Drop_pric)

     values('server.domain','customer','custom','y','y','y','y','y','y');

flush privileges;

이것도 마찬가지로 flush pricileges; 를 반드시 해줘야 적용이 된다~

한가지 팁이라면... % 와일드 카드 문자를 사용하여 grant명령문을 입력하면 모든 곳에서 허용이 된다.

예) grant ... on *.* to 'user'@'%.mydomain.com' identified by 'myboss';

   (이렇게 하면 .mydomain.com앞에  뭐가 붙어서 오든지 허용이 된다는 뜻.)

    grant ... on test_%.* to ... identified by ...;

   (이건 데이터베이스 이름이 test_ 로 시작하는 모든것에 사용권한을 부여한다는 뜻이다.)

 원본 레퍼런스 참조.

 

mysql 실행

>mysql -u 계정명 -p 

>비밀번호


>show databases;

>use 데이터베이스명;

>show tables;

>select 속성1, 속성2, ...., 속성n from 테이블명;

>select * from 테이블명;


사용자 계정 추가

>use mysql;

>insert into user(host,user,password) values('localhost','계정명',password('비밀번호'));로컬접근 허용

>insert into user(host,user,password) values('%','계정명',password('비밀번호'));외부접근 허용

>flush privileges;


db 생성후 db에 계정연결

>grant all privileges on DB명.* to 계정명@localhost identified by '비밀번호' with grant option;

>flush privileges;



- 특정 사용자의 외부접근을 허용 (이미 만들어진 계정에서)

>update user set host='%' where host='localhost' and user='계정명';

>flush privileges;

 작성일 : 12-02-16
 조회 : 1,201  
1. FTP 환경설정파일 수정

~# vi /etc/vsftpd/vsftpd.conf

# 문서하단에 추가

chroot_local_user=YES
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd/chroot_list


2. chroot_list 파일안에, root 추가 (이파일안에 등록된 USER는 상위디렉토리 접근제한을 받지 않는다.)

~# vi /etc/vsftpd/chroot_list

root


vsftp, ftp 사용자 폴더를 제외한 다른 폴더 접근제한

1)파일을 편집
/etc/vsftpd/vsftpd.conf

chroot_local_user=YES 추가

2)ftp demon restart
/etc/init.d/vsftpd restart


*다음의 파일에 등록된 사용자들은 FTP 접속이 불가능
/etc/vsftpd.ftpusers

/etc/vsftpd.user_list

-------------------------------------------------------------------------------

1. ftpusers와 vsftpd.chroot_list 차이 

/etc/ftpusers 과 chroot_list_file=/etc/vsftpd.chroot_list 파일은 용도가 다릅니다. 

* /etc/ftpusers : 이건 접속을 제한하는 것입니다
. 즉, 여기에 등록된 ID는 ftp 접속 자체를 할 수 없습니다. 
* /etc/vsftpd.chroot_list : 여기에 써진 ID는 접속할 수 있습니다. 
다만, 자신의 홈디렉토리를 벗어날 수(상위디렉토리로 갈 수) 없습니다.
 
이를테면 홈이 /home/truefeel/ 일 때 /home/truefeel/ 를 벗어난 /etc, /home, /usr 등을 갈 수 없다는 것입니다. 
이해되시나요? 
보안상 홈보다 상위 디렉토리로 이동하는 것을 제한하는 경우가 많습니다. 

2. chroot_local_user 와 chroot_list_enable 설정을 함께 사용할 때 

제가 쓴 글을 다시 인용하여 설명하겠습니다. 

인용:

3) 사용자가 홈디렉토리를 못 벗어나게 하고 싶는데? 

 /etc/vsftpd.conf에 다음을 추가하면, 모든 사용자는 자신의 홈디렉토리만 접근할 수 있다. 

 chroot_local_user=YES 

 또한 특정 사용자로만 제한을 하고 싶다면 다음과 같이 한다. /etc/vsftpd.chroot_list에는 제한할 
 사용자 ID를 한줄에 하나씩 나열하면 된다. 

 chroot_list_enable=YES 
 chroot_list_file=/etc/vsftpd.chroot_list 

 주의할 것은 chroot_local_user=YES와 chroot_list_enable=YES를 함께 사용할 경우에는 
 /etc/vsftpd.chroot_list에 포함된 사용자 ID만 제한없이 홈디렉토리를 벗어날 수 있다. 
 즉, 반대로 작용한다. 



위의 내용을 설정부분만 뽑으면 이렇습니다. 

1) 조건 1 
코드:

chroot_local_user=NO 
chroot_list_enable=YES 
chroot_list_file=/etc/vsftpd/chroot_list 



이런 경우는 /etc/vsftpd/chroot_list 파일에 설정한 ID는 홈디렉토리를 벗어날 수(즉, 상위로 갈 수) 없습니다. 

2) 조건 2 
코드:

chroot_local_user=YES 
chroot_list_enable=YES 
chroot_list_file=/etc/vsftpd/chroot_list 



이런 경우는 
/etc/vsftpd/chroot_list 파일에 설정한 ID만 홈디렉토리를 벗어날 수(즉, 상위로 갈 수) 있습니다. 
즉, 조건1과는 반대로 되는 것입니다. 


3. 특정 IP를 막을 때 

레드햇의 자체 vsftpd rpm은 tcp wrapper를 통해 IP제한을 할 수 있습니다. 
님의 말씀대로 이걸 이용하거나 iptables를 통해서 막으면 되겠네요.


sudo 권한이 있어야한다.


사용자추가


$ adduser NewId


하면 알아서 비밀번호 설정 가능


그룹생성


$ groupadd NewGroup


새사용자 그룹지정


$ vi /etc/group


NewGroup:x:1002:

이있는데 뒤에다 사용자 아이디를 써준다

NewGroup:x:1002:NewId

그리고 저장.

NewGroupDir이란 디렉토리의 소유권을 NewGroup으로 줌


$chown -R root:NewGroup NewGroupDir/


그리고 폴더 접근권한을 설정한다


$chmod -R 700 NewGroupDir/



접근권한 참고

r : Read  = 4
w : Write = 2
x : eXcute = 1

-rwxrwxrwx   ( 777 )
-r--r--r--  ( 444 )
-rwx--x--x ( 711 )

2~4필드 : 소유주 ( User ) 권한
5~7필드 : 그룹 ( Group )  권한
8~10필드 : 나머지 ( Others ) 권한


 


+ Recent posts